blob: a7cbeac723987d93746fe35a84de2f4d20043a58 [file] [log] [blame]
robertphillipsea461502015-05-26 11:38:03 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkDrawable.h"
9#include "include/gpu/GrBackendSemaphore.h"
10#include "include/gpu/GrRenderTarget.h"
11#include "include/private/GrAuditTrail.h"
12#include "include/private/GrColor.h"
13#include "include/private/GrOpList.h"
14#include "include/private/GrRecordingContext.h"
15#include "include/private/SkShadowFlags.h"
16#include "include/utils/SkShadowUtils.h"
Brian Salomoncd734f62019-05-10 16:32:54 -040017#include "src/core/SkAutoPixmapStorage.h"
18#include "src/core/SkConvertPixels.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/core/SkDrawShadowInfo.h"
20#include "src/core/SkGlyphRunPainter.h"
21#include "src/core/SkLatticeIter.h"
22#include "src/core/SkMatrixPriv.h"
23#include "src/core/SkRRectPriv.h"
24#include "src/core/SkSurfacePriv.h"
25#include "src/gpu/GrAppliedClip.h"
26#include "src/gpu/GrBlurUtils.h"
27#include "src/gpu/GrCaps.h"
28#include "src/gpu/GrContextPriv.h"
29#include "src/gpu/GrDrawingManager.h"
30#include "src/gpu/GrFixedClip.h"
31#include "src/gpu/GrGpuResourcePriv.h"
32#include "src/gpu/GrMemoryPool.h"
33#include "src/gpu/GrPathRenderer.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050034#include "src/gpu/GrRecordingContextPriv.h"
Mike Klein4b432fa2019-06-06 11:44:05 -050035#include "src/gpu/GrRenderTargetContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050036#include "src/gpu/GrRenderTargetContextPriv.h"
37#include "src/gpu/GrResourceProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050038#include "src/gpu/GrStencilAttachment.h"
39#include "src/gpu/GrStyle.h"
40#include "src/gpu/GrTracing.h"
41#include "src/gpu/SkGr.h"
Brian Salomon031b0ba2019-05-23 11:05:26 -040042#include "src/gpu/effects/GrBicubicEffect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050043#include "src/gpu/effects/GrRRectEffect.h"
44#include "src/gpu/effects/GrTextureDomain.h"
Brian Salomon024bd002019-06-11 11:38:16 -040045#include "src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040046#include "src/gpu/geometry/GrQuad.h"
Michael Ludwig663afe52019-06-03 16:46:19 -040047#include "src/gpu/geometry/GrShape.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050048#include "src/gpu/ops/GrAtlasTextOp.h"
49#include "src/gpu/ops/GrClearOp.h"
50#include "src/gpu/ops/GrClearStencilClipOp.h"
51#include "src/gpu/ops/GrDebugMarkerOp.h"
52#include "src/gpu/ops/GrDrawAtlasOp.h"
53#include "src/gpu/ops/GrDrawOp.h"
54#include "src/gpu/ops/GrDrawVerticesOp.h"
55#include "src/gpu/ops/GrDrawableOp.h"
56#include "src/gpu/ops/GrFillRRectOp.h"
57#include "src/gpu/ops/GrFillRectOp.h"
58#include "src/gpu/ops/GrLatticeOp.h"
59#include "src/gpu/ops/GrOp.h"
60#include "src/gpu/ops/GrOvalOpFactory.h"
61#include "src/gpu/ops/GrRegionOp.h"
62#include "src/gpu/ops/GrSemaphoreOp.h"
63#include "src/gpu/ops/GrShadowRRectOp.h"
64#include "src/gpu/ops/GrStencilPathOp.h"
65#include "src/gpu/ops/GrStrokeRectOp.h"
66#include "src/gpu/ops/GrTextureOp.h"
Brian Salomonab32f652019-05-10 14:24:50 -040067#include "src/gpu/ops/GrTransferFromOp.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050068#include "src/gpu/text/GrTextContext.h"
69#include "src/gpu/text/GrTextTarget.h"
Brian Salomonf18b1d82017-10-27 11:30:49 -040070
Herb Derbyc1b482c2018-08-09 15:02:27 -040071class GrRenderTargetContext::TextTarget : public GrTextTarget {
Brian Salomonf18b1d82017-10-27 11:30:49 -040072public:
73 TextTarget(GrRenderTargetContext* renderTargetContext)
Herb Derbyc1b482c2018-08-09 15:02:27 -040074 : GrTextTarget(renderTargetContext->width(), renderTargetContext->height(),
Robert Phillips7e90be92019-02-15 12:22:59 -050075 renderTargetContext->colorSpaceInfo())
Herb Derby74c6ed32018-07-28 18:07:54 -040076 , fRenderTargetContext(renderTargetContext)
Herb Derby65956872018-08-21 16:55:04 -040077 , fGlyphPainter{*renderTargetContext}{}
Brian Salomonf18b1d82017-10-27 11:30:49 -040078
Robert Phillips7c525e62018-06-12 10:11:12 -040079 void addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) override {
Brian Salomonf18b1d82017-10-27 11:30:49 -040080 fRenderTargetContext->addDrawOp(clip, std::move(op));
81 }
82
Robert Phillips46a13382018-08-23 13:53:01 -040083 void drawShape(const GrClip& clip, const SkPaint& paint,
84 const SkMatrix& viewMatrix, const GrShape& shape) override {
Robert Phillips27927a52018-08-20 13:18:12 -040085 GrBlurUtils::drawShapeWithMaskFilter(fRenderTargetContext->fContext, fRenderTargetContext,
86 clip, paint, viewMatrix, shape);
Brian Salomonf18b1d82017-10-27 11:30:49 -040087 }
88
89 void makeGrPaint(GrMaskFormat maskFormat, const SkPaint& skPaint, const SkMatrix& viewMatrix,
Robert Phillips7c525e62018-06-12 10:11:12 -040090 GrPaint* grPaint) override {
Robert Phillips69893702019-02-22 11:16:30 -050091 auto context = fRenderTargetContext->fContext;
Brian Salomonf18b1d82017-10-27 11:30:49 -040092 const GrColorSpaceInfo& colorSpaceInfo = fRenderTargetContext->colorSpaceInfo();
93 if (kARGB_GrMaskFormat == maskFormat) {
94 SkPaintToGrPaintWithPrimitiveColor(context, colorSpaceInfo, skPaint, grPaint);
95 } else {
96 SkPaintToGrPaint(context, colorSpaceInfo, skPaint, viewMatrix, grPaint);
97 }
98 }
99
Robert Phillips69893702019-02-22 11:16:30 -0500100 GrRecordingContext* getContext() override {
Robert Phillips7c525e62018-06-12 10:11:12 -0400101 return fRenderTargetContext->fContext;
102 }
103
Herb Derby65956872018-08-21 16:55:04 -0400104 SkGlyphRunListPainter* glyphPainter() override {
105 return &fGlyphPainter;
Herb Derby74c6ed32018-07-28 18:07:54 -0400106 }
107
Brian Salomonf18b1d82017-10-27 11:30:49 -0400108private:
109 GrRenderTargetContext* fRenderTargetContext;
Herb Derby65956872018-08-21 16:55:04 -0400110 SkGlyphRunListPainter fGlyphPainter;
Herb Derby74c6ed32018-07-28 18:07:54 -0400111
Brian Salomonf18b1d82017-10-27 11:30:49 -0400112};
joshualittbc907352016-01-13 06:45:40 -0800113
Robert Phillips72152832017-01-25 17:31:35 -0500114#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
joshualitt1de610a2016-01-06 08:26:09 -0800115#define ASSERT_SINGLE_OWNER \
Robert Phillipsa90aa2b2017-04-10 08:19:26 -0400116 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
robertphillips391395d2016-03-02 09:26:36 -0800117#define ASSERT_SINGLE_OWNER_PRIV \
Robert Phillipsa90aa2b2017-04-10 08:19:26 -0400118 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());)
Robert Phillips69893702019-02-22 11:16:30 -0500119#define RETURN_IF_ABANDONED if (fContext->priv().abandoned()) { return; }
120#define RETURN_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return; }
121#define RETURN_FALSE_IF_ABANDONED if (fContext->priv().abandoned()) { return false; }
122#define RETURN_FALSE_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return false; }
123#define RETURN_NULL_IF_ABANDONED if (fContext->priv().abandoned()) { return nullptr; }
robertphillipsea461502015-05-26 11:38:03 -0700124
Brian Salomone225b562017-06-14 13:00:03 -0400125//////////////////////////////////////////////////////////////////////////////
126
robertphillipsea461502015-05-26 11:38:03 -0700127class AutoCheckFlush {
128public:
halcanary9d524f22016-03-29 09:03:52 -0700129 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
robertphillips77a2e522015-10-17 07:43:27 -0700130 SkASSERT(fDrawingManager);
131 }
bsalomonb77a9072016-09-07 10:02:04 -0700132 ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
robertphillipsea461502015-05-26 11:38:03 -0700133
134private:
robertphillips77a2e522015-10-17 07:43:27 -0700135 GrDrawingManager* fDrawingManager;
robertphillipsea461502015-05-26 11:38:03 -0700136};
137
Robert Phillipsf2361d22016-10-25 14:20:06 -0400138// In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress
Brian Osman11052242016-10-27 14:47:55 -0400139// GrOpLists to be picked up and added to by renderTargetContexts lower in the call
Robert Phillipsf2361d22016-10-25 14:20:06 -0400140// stack. When this occurs with a closed GrOpList, a new one will be allocated
Brian Osman11052242016-10-27 14:47:55 -0400141// when the renderTargetContext attempts to use it (via getOpList).
Robert Phillips69893702019-02-22 11:16:30 -0500142GrRenderTargetContext::GrRenderTargetContext(GrRecordingContext* context,
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400143 sk_sp<GrRenderTargetProxy> rtp,
Brian Osman11052242016-10-27 14:47:55 -0400144 sk_sp<SkColorSpace> colorSpace,
145 const SkSurfaceProps* surfaceProps,
Robert Phillips941d1442017-06-14 16:37:02 -0400146 bool managedOpList)
Robert Phillips0d075de2019-03-04 11:08:13 -0500147 : GrSurfaceContext(context, rtp->config(), std::move(colorSpace))
Brian Salomonf3569f02017-10-24 12:52:33 -0400148 , fRenderTargetProxy(std::move(rtp))
149 , fOpList(sk_ref_sp(fRenderTargetProxy->getLastRenderTargetOpList()))
Brian Salomonf3569f02017-10-24 12:52:33 -0400150 , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
151 , fManagedOpList(managedOpList) {
Brian Salomonf18b1d82017-10-27 11:30:49 -0400152 fTextTarget.reset(new TextTarget(this));
robertphillips2e1e51f2015-10-15 08:01:48 -0700153 SkDEBUGCODE(this->validate();)
robertphillipsea461502015-05-26 11:38:03 -0700154}
155
robertphillips2e1e51f2015-10-15 08:01:48 -0700156#ifdef SK_DEBUG
Brian Osman11052242016-10-27 14:47:55 -0400157void GrRenderTargetContext::validate() const {
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400158 SkASSERT(fRenderTargetProxy);
159 fRenderTargetProxy->validate(fContext);
robertphillipsa106c622015-10-16 09:07:06 -0700160
Robert Phillipsf2361d22016-10-25 14:20:06 -0400161 if (fOpList && !fOpList->isClosed()) {
Robert Phillipsdc83b892017-04-13 12:23:54 -0400162 SkASSERT(fRenderTargetProxy->getLastOpList() == fOpList.get());
robertphillipsa106c622015-10-16 09:07:06 -0700163 }
robertphillips2e1e51f2015-10-15 08:01:48 -0700164}
165#endif
166
Brian Osman11052242016-10-27 14:47:55 -0400167GrRenderTargetContext::~GrRenderTargetContext() {
joshualitt1de610a2016-01-06 08:26:09 -0800168 ASSERT_SINGLE_OWNER
robertphillipsa106c622015-10-16 09:07:06 -0700169}
170
Chris Dalton7d6748e2019-03-13 00:34:52 -0600171inline GrAAType GrRenderTargetContext::chooseAAType(GrAA aa) {
172 auto fsaaType = this->fsaaType();
173 if (GrAA::kNo == aa) {
174 // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
175 // that.
176 if (fsaaType == GrFSAAType::kUnifiedMSAA && !this->caps()->multisampleDisableSupport()) {
177 return GrAAType::kMSAA;
178 }
179 return GrAAType::kNone;
180 }
181 switch (fsaaType) {
182 case GrFSAAType::kNone:
183 case GrFSAAType::kMixedSamples:
184 return GrAAType::kCoverage;
185 case GrFSAAType::kUnifiedMSAA:
186 return GrAAType::kMSAA;
187 }
188 SK_ABORT("Unexpected fsaa type");
189 return GrAAType::kNone;
190}
191
192static inline GrPathRenderer::AATypeFlags choose_path_aa_type_flags(
193 GrAA aa, GrFSAAType fsaaType, const GrCaps& caps) {
194 using AATypeFlags = GrPathRenderer::AATypeFlags;
195 if (GrAA::kNo == aa) {
196 // On some devices we cannot disable MSAA if it is enabled so we make the AA type flags
197 // reflect that.
198 if (fsaaType == GrFSAAType::kUnifiedMSAA && !caps.multisampleDisableSupport()) {
199 return AATypeFlags::kMSAA;
200 }
201 return AATypeFlags::kNone;
202 }
203 switch (fsaaType) {
204 case GrFSAAType::kNone:
205 return AATypeFlags::kCoverage;
206 case GrFSAAType::kMixedSamples:
207 return AATypeFlags::kCoverage | AATypeFlags::kMixedSampledStencilThenCover;
208 case GrFSAAType::kUnifiedMSAA:
209 return AATypeFlags::kMSAA;
210 }
211 SK_ABORT("Invalid GrFSAAType.");
212 return AATypeFlags::kNone;
213}
214
Robert Phillipsf200a902017-01-30 13:27:37 -0500215GrTextureProxy* GrRenderTargetContext::asTextureProxy() {
Robert Phillipseaa86252016-11-08 13:49:39 +0000216 return fRenderTargetProxy->asTextureProxy();
217}
218
Greg Daniele252f082017-10-23 16:05:23 -0400219const GrTextureProxy* GrRenderTargetContext::asTextureProxy() const {
220 return fRenderTargetProxy->asTextureProxy();
221}
222
Robert Phillipsf200a902017-01-30 13:27:37 -0500223sk_sp<GrTextureProxy> GrRenderTargetContext::asTextureProxyRef() {
224 return sk_ref_sp(fRenderTargetProxy->asTextureProxy());
225}
226
Greg Daniele252f082017-10-23 16:05:23 -0400227GrMipMapped GrRenderTargetContext::mipMapped() const {
228 if (const GrTextureProxy* proxy = this->asTextureProxy()) {
229 return proxy->mipMapped();
230 }
231 return GrMipMapped::kNo;
232}
233
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400234GrRenderTargetOpList* GrRenderTargetContext::getRTOpList() {
joshualitt1de610a2016-01-06 08:26:09 -0800235 ASSERT_SINGLE_OWNER
robertphillipsa106c622015-10-16 09:07:06 -0700236 SkDEBUGCODE(this->validate();)
237
Robert Phillipsf2361d22016-10-25 14:20:06 -0400238 if (!fOpList || fOpList->isClosed()) {
Michael Ludwig6e17f1d2019-05-15 14:00:20 +0000239 fOpList = this->drawingManager()->newRTOpList(fRenderTargetProxy, fManagedOpList);
robertphillipsa106c622015-10-16 09:07:06 -0700240 }
241
Robert Phillipsdc83b892017-04-13 12:23:54 -0400242 return fOpList.get();
robertphillipsa106c622015-10-16 09:07:06 -0700243}
244
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400245GrOpList* GrRenderTargetContext::getOpList() {
246 return this->getRTOpList();
robertphillipsea461502015-05-26 11:38:03 -0700247}
248
Herb Derbycddab252018-07-16 11:19:04 -0400249void GrRenderTargetContext::drawGlyphRunList(
250 const GrClip& clip, const SkMatrix& viewMatrix,
Robert Phillipse4643cc2018-08-14 13:01:29 -0400251 const SkGlyphRunList& blob) {
joshualitt1de610a2016-01-06 08:26:09 -0800252 ASSERT_SINGLE_OWNER
robertphillips2d70dcb2015-10-06 07:38:23 -0700253 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700254 SkDEBUGCODE(this->validate();)
Herb Derbycddab252018-07-16 11:19:04 -0400255 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawGlyphRunList", fContext);
robertphillips2d70dcb2015-10-06 07:38:23 -0700256
Greg Danielbe7fc462019-01-03 16:40:42 -0500257 // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
258 // secondary command buffers because it would require stopping and starting a render pass which
259 // we don't have access to.
260 if (this->wrapsVkSecondaryCB()) {
261 return;
262 }
263
Herb Derby26cbe512018-05-24 14:39:01 -0400264 GrTextContext* atlasTextContext = this->drawingManager()->getTextContext();
Herb Derbycddab252018-07-16 11:19:04 -0400265 atlasTextContext->drawGlyphRunList(fContext, fTextTarget.get(), clip, viewMatrix,
Robert Phillipse4643cc2018-08-14 13:01:29 -0400266 fSurfaceProps, blob);
robertphillipsea461502015-05-26 11:38:03 -0700267}
268
Brian Osman11052242016-10-27 14:47:55 -0400269void GrRenderTargetContext::discard() {
joshualitt1de610a2016-01-06 08:26:09 -0800270 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700271 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700272 SkDEBUGCODE(this->validate();)
Robert Phillips6b47c7d2017-08-29 07:24:09 -0400273 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "discard", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -0700274
Robert Phillips72152832017-01-25 17:31:35 -0500275 AutoCheckFlush acf(this->drawingManager());
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400276
Robert Phillips380b90c2017-08-30 07:41:07 -0400277 this->getRTOpList()->discard();
robertphillipsea461502015-05-26 11:38:03 -0700278}
279
Brian Osman11052242016-10-27 14:47:55 -0400280void GrRenderTargetContext::clear(const SkIRect* rect,
Brian Osman9a9baae2018-11-05 15:06:26 -0500281 const SkPMColor4f& color,
Chris Dalton344e9032017-12-11 15:42:09 -0700282 CanClearFullscreen canClearFullscreen) {
joshualitt1de610a2016-01-06 08:26:09 -0800283 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700284 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700285 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400286 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "clear", fContext);
robertphillipsea461502015-05-26 11:38:03 -0700287
Robert Phillips72152832017-01-25 17:31:35 -0500288 AutoCheckFlush acf(this->drawingManager());
Chris Dalton344e9032017-12-11 15:42:09 -0700289 this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color,
290 canClearFullscreen);
csmartdalton29df7602016-08-31 11:55:52 -0700291}
robertphillips9199a9f2016-07-13 07:48:43 -0700292
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500293void GrRenderTargetContextPriv::clear(const GrFixedClip& clip,
294 const SkPMColor4f& color,
295 CanClearFullscreen canClearFullscreen) {
296 ASSERT_SINGLE_OWNER_PRIV
297 RETURN_IF_ABANDONED_PRIV
298 SkDEBUGCODE(fRenderTargetContext->validate();)
299 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clear",
300 fRenderTargetContext->fContext);
301
302 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
303 fRenderTargetContext->internalClear(clip, color, canClearFullscreen);
304}
305
306static void clear_to_grpaint(const SkPMColor4f& color, GrPaint* paint) {
307 paint->setColor4f(color);
308 if (color.isOpaque()) {
309 // Can just rely on the src-over blend mode to do the right thing
310 paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
311 } else {
312 // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
313 // were src blended
314 paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
315 }
316}
317
318void GrRenderTargetContext::internalClear(const GrFixedClip& clip,
319 const SkPMColor4f& color,
320 CanClearFullscreen canClearFullscreen) {
321 bool isFull = false;
322 if (!clip.hasWindowRectangles()) {
Robert Phillips0e35ce22019-04-05 10:57:28 -0400323 // TODO: wrt the shouldInitializeTextures path, it would be more performant to
324 // only clear the entire target if we knew it had not been cleared before. As
325 // is this could end up doing a lot of redundant clears.
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500326 isFull = !clip.scissorEnabled() ||
327 (CanClearFullscreen::kYes == canClearFullscreen &&
Robert Phillips0e35ce22019-04-05 10:57:28 -0400328 (this->caps()->preferFullscreenClears() || this->caps()->shouldInitializeTextures())) ||
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500329 clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
330 }
331
332 if (isFull) {
333 if (this->getRTOpList()->resetForFullscreenClear() &&
334 !this->caps()->performColorClearsAsDraws()) {
335 // The op list was emptied and native clears are allowed, so just use the load op
336 this->getRTOpList()->setColorLoadOp(GrLoadOp::kClear, color);
337 return;
338 } else {
339 // Will use an op for the clear, reset the load op to discard since the op will
340 // blow away the color buffer contents
341 this->getRTOpList()->setColorLoadOp(GrLoadOp::kDiscard);
342 }
343
344 // Must add an op to the list (either because we couldn't use a load op, or because the
345 // clear load op isn't supported)
346 if (this->caps()->performColorClearsAsDraws()) {
347 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
348 GrPaint paint;
349 clear_to_grpaint(color, &paint);
350 this->addDrawOp(GrFixedClip::Disabled(),
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400351 GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
352 rtRect));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500353 } else {
354 this->getRTOpList()->addOp(GrClearOp::Make(fContext, SkIRect::MakeEmpty(), color,
355 /* fullscreen */ true), *this->caps());
356 }
357 } else {
358 if (this->caps()->performPartialClearsAsDraws()) {
359 // performPartialClearsAsDraws() also returns true if any clear has to be a draw.
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500360 GrPaint paint;
361 clear_to_grpaint(color, &paint);
362
Michael Ludwig64b28a72019-05-28 12:02:00 -0400363 this->addDrawOp(clip,
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400364 GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
365 SkRect::Make(clip.scissorRect())));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500366 } else {
367 std::unique_ptr<GrOp> op(GrClearOp::Make(fContext, clip, color,
368 this->asSurfaceProxy()));
369 // This version of the clear op factory can return null if the clip doesn't intersect
370 // with the surface proxy's boundary
371 if (!op) {
372 return;
373 }
374 this->getRTOpList()->addOp(std::move(op), *this->caps());
375 }
376 }
377}
378
Brian Osman9a9baae2018-11-05 15:06:26 -0500379void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const SkPMColor4f& color) {
Robert Phillips784b7bf2016-12-09 13:35:02 -0500380 ASSERT_SINGLE_OWNER_PRIV
381 RETURN_IF_ABANDONED_PRIV
382 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400383 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "absClear",
384 fRenderTargetContext->fContext);
Robert Phillips784b7bf2016-12-09 13:35:02 -0500385
Robert Phillips72152832017-01-25 17:31:35 -0500386 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
Robert Phillips784b7bf2016-12-09 13:35:02 -0500387
Brian Salomonbb5711a2017-05-17 13:49:59 -0400388 SkIRect rtRect = SkIRect::MakeWH(fRenderTargetContext->fRenderTargetProxy->worstCaseWidth(),
389 fRenderTargetContext->fRenderTargetProxy->worstCaseHeight());
Robert Phillips784b7bf2016-12-09 13:35:02 -0500390
391 if (clearRect) {
392 if (clearRect->contains(rtRect)) {
393 clearRect = nullptr; // full screen
394 } else {
395 if (!rtRect.intersect(*clearRect)) {
396 return;
397 }
398 }
399 }
400
401 // TODO: in a post-MDB world this should be handled at the OpList level.
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500402 // This makes sure to always add an op to the list, instead of marking the clear as a load op.
403 // This code follows very similar logic to internalClear() below, but critical differences are
404 // highlighted in line related to absClear()'s unique behavior.
405 if (clearRect) {
406 if (fRenderTargetContext->caps()->performPartialClearsAsDraws()) {
Ethan Nicholas56d19a52018-10-15 11:26:20 -0400407 GrPaint paint;
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500408 clear_to_grpaint(color, &paint);
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400409
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500410 // Use the disabled clip; the rect geometry already matches the clear rectangle and
411 // if it were added to a scissor, that would be intersected with the logical surface
412 // bounds and not the worst case dimensions required here.
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400413 fRenderTargetContext->addDrawOp(
414 GrFixedClip::Disabled(),
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400415 GrFillRectOp::MakeNonAARect(fRenderTargetContext->fContext, std::move(paint),
416 SkMatrix::I(), SkRect::Make(rtRect)));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500417 } else {
418 // Must use the ClearOp factory that takes a boolean (false) instead of a surface
419 // proxy. The surface proxy variant would intersect the clip rect with its logical
420 // bounds, which is not desired in this special case.
421 fRenderTargetContext->getRTOpList()->addOp(
422 GrClearOp::Make(fRenderTargetContext->fContext, rtRect, color,
423 /* fullscreen */ false),
424 *fRenderTargetContext->caps());
csmartdalton29df7602016-08-31 11:55:52 -0700425 }
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500426 } else {
427 // Reset the oplist like in internalClear(), but do not rely on a load op for the clear
428 fRenderTargetContext->getRTOpList()->resetForFullscreenClear();
429 fRenderTargetContext->getRTOpList()->setColorLoadOp(GrLoadOp::kDiscard);
430
431 if (fRenderTargetContext->caps()->performColorClearsAsDraws()) {
432 // This draws a quad covering the worst case dimensions instead of just the logical
433 // width and height like in internalClear().
434 GrPaint paint;
435 clear_to_grpaint(color, &paint);
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400436 fRenderTargetContext->addDrawOp(
437 GrFixedClip::Disabled(),
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400438 GrFillRectOp::MakeNonAARect(fRenderTargetContext->fContext, std::move(paint),
439 SkMatrix::I(), SkRect::Make(rtRect)));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500440 } else {
441 // Nothing special about this path in absClear compared to internalClear()
442 fRenderTargetContext->getRTOpList()->addOp(
443 GrClearOp::Make(fRenderTargetContext->fContext, SkIRect::MakeEmpty(), color,
444 /* fullscreen */ true),
445 *fRenderTargetContext->caps());
Ethan Nicholas56d19a52018-10-15 11:26:20 -0400446 }
robertphillips9199a9f2016-07-13 07:48:43 -0700447 }
robertphillipsea461502015-05-26 11:38:03 -0700448}
449
Brian Osman11052242016-10-27 14:47:55 -0400450void GrRenderTargetContext::drawPaint(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -0500451 GrPaint&& paint,
Brian Osman11052242016-10-27 14:47:55 -0400452 const SkMatrix& viewMatrix) {
joshualitt1de610a2016-01-06 08:26:09 -0800453 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700454 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700455 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400456 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPaint", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -0700457
robertphillipsea461502015-05-26 11:38:03 -0700458 // set rect to be big enough to fill the space, but not super-huge, so we
459 // don't overflow fixed-point implementations
robertphillips13a7eee2016-08-31 15:06:24 -0700460
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400461 SkRect r = fRenderTargetProxy->getBoundsRect();
robertphillipsea461502015-05-26 11:38:03 -0700462
Michael Ludwig61a16512019-01-15 11:15:13 -0500463 // Check if we can optimize a clipped drawPaint(). We only do the transformation when there are
464 // no fragment processors because they may depend on having correct local coords and this path
465 // draws in device space without a local matrix. It currently handles converting clipRRect()
466 // to drawRRect() and solid colors to screen-filling drawRects() (which are then converted into
467 // clears if possible in drawRect).
Michael Ludwig3d6390e2018-10-09 11:45:16 -0400468 if (!paint.numTotalFragmentProcessors()) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500469 SkRRect rrect;
470 GrAA aa = GrAA::kNo;
471 if (clip.isRRect(r, &rrect, &aa)) {
472 if (rrect.isRect()) {
473 // Use drawFilledRect() with no clip and the reduced rectangle
474 this->drawFilledRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect.rect());
475 } else {
476 // Use drawRRect() with no clip
477 this->drawRRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect,
478 GrStyle::SimpleFill());
479 }
480 } else {
481 // Use drawFilledRect() with no view matrix to draw a fullscreen quad, but preserve
482 // the clip. Since the paint has no FPs we can drop the view matrix without worrying
483 // about local coordinates. If the clip is simple, drawFilledRect() will turn this into
484 // a clear or a scissored clear.
485 this->drawFilledRect(clip, std::move(paint), aa, SkMatrix::I(), r);
Michael Ludwig3d6390e2018-10-09 11:45:16 -0400486 }
Michael Ludwig61a16512019-01-15 11:15:13 -0500487 return;
bsalomoncb31e512016-08-26 10:48:19 -0700488 }
489
Michael Ludwig61a16512019-01-15 11:15:13 -0500490 // Since the paint is not trivial, there's no way at this point drawRect() could have converted
491 // this drawPaint() into an optimized clear. drawRect() would then use GrFillRectOp without
492 // a local matrix, so we can simplify things and use the local matrix variant to draw a screen
493 // filling rect with the inverse view matrix for local coords, which works for all matrix
494 // conditions.
495 SkMatrix localMatrix;
496 if (!viewMatrix.invert(&localMatrix)) {
497 return;
robertphillipsea461502015-05-26 11:38:03 -0700498 }
Michael Ludwig61a16512019-01-15 11:15:13 -0500499
500 AutoCheckFlush acf(this->drawingManager());
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400501 std::unique_ptr<GrDrawOp> op = GrFillRectOp::Make(
Michael Ludwig64b28a72019-05-28 12:02:00 -0400502 fContext, std::move(paint), GrAAType::kNone, GrQuadAAFlags::kNone,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400503 GrQuad(r), GrQuad::MakeFromRect(r, localMatrix));
Michael Ludwig61a16512019-01-15 11:15:13 -0500504 this->addDrawOp(clip, std::move(op));
robertphillipsea461502015-05-26 11:38:03 -0700505}
506
robertphillipsea461502015-05-26 11:38:03 -0700507static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
508 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
509 point.fY >= rect.fTop && point.fY <= rect.fBottom;
510}
511
csmartdalton97f6cd52016-07-13 13:37:08 -0700512// Attempts to crop a rect and optional local rect to the clip boundaries.
513// Returns false if the draw can be skipped entirely.
robertphillips13a7eee2016-08-31 15:06:24 -0700514static bool crop_filled_rect(int width, int height, const GrClip& clip,
csmartdalton97f6cd52016-07-13 13:37:08 -0700515 const SkMatrix& viewMatrix, SkRect* rect,
516 SkRect* localRect = nullptr) {
517 if (!viewMatrix.rectStaysRect()) {
518 return true;
519 }
520
csmartdalton97f6cd52016-07-13 13:37:08 -0700521 SkIRect clipDevBounds;
522 SkRect clipBounds;
csmartdalton97f6cd52016-07-13 13:37:08 -0700523
robertphillips13a7eee2016-08-31 15:06:24 -0700524 clip.getConservativeBounds(width, height, &clipDevBounds);
reeda39667c2016-08-22 06:39:49 -0700525 if (!SkMatrixPriv::InverseMapRect(viewMatrix, &clipBounds, SkRect::Make(clipDevBounds))) {
526 return false;
527 }
csmartdalton97f6cd52016-07-13 13:37:08 -0700528
529 if (localRect) {
530 if (!rect->intersects(clipBounds)) {
531 return false;
532 }
Michael Ludwig904657d2019-04-12 10:57:24 -0400533 // localRect is force-sorted after clipping, so this is a sanity check to make sure callers
534 // aren't intentionally using inverted local rectangles.
535 SkASSERT(localRect->isSorted());
csmartdalton97f6cd52016-07-13 13:37:08 -0700536 const SkScalar dx = localRect->width() / rect->width();
537 const SkScalar dy = localRect->height() / rect->height();
538 if (clipBounds.fLeft > rect->fLeft) {
539 localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx;
540 rect->fLeft = clipBounds.fLeft;
541 }
542 if (clipBounds.fTop > rect->fTop) {
543 localRect->fTop += (clipBounds.fTop - rect->fTop) * dy;
544 rect->fTop = clipBounds.fTop;
545 }
546 if (clipBounds.fRight < rect->fRight) {
547 localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx;
548 rect->fRight = clipBounds.fRight;
549 }
550 if (clipBounds.fBottom < rect->fBottom) {
551 localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy;
552 rect->fBottom = clipBounds.fBottom;
553 }
Michael Ludwig904657d2019-04-12 10:57:24 -0400554 // Ensure local coordinates remain sorted after clipping. If the original dstRect was very
555 // large, numeric precision can invert the localRect
556 localRect->sort();
csmartdalton97f6cd52016-07-13 13:37:08 -0700557 return true;
558 }
559
560 return rect->intersect(clipBounds);
561}
562
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400563GrQuadAAFlags set_edge_flag(GrQuadAAFlags currentFlags, GrQuadAAFlags edge, GrAA edgeState) {
564 if (edgeState == GrAA::kNo) {
565 // Turn off 'edge' in currentFlags
566 return currentFlags & (~edge);
567 } else {
568 // Turn on 'edge' in currentFlags
569 return currentFlags | edge;
570 }
571}
572
Michael Ludwig61a16512019-01-15 11:15:13 -0500573bool GrRenderTargetContext::drawFilledRectAsClear(const GrClip& clip, GrPaint&& paint, GrAA aa,
574 const SkMatrix& viewMatrix, const SkRect& rect) {
575 // Rules for a filled rect to become a clear [+scissor]:
576 // 1. The paint is a constant blend color with no other FPs
577 // 2. The view matrix maps rectangles to rectangles, or the transformed quad fully covers
578 // the render target (or clear region in #3).
579 // 3. The clip is an intersection of rectangles, so the clear region will be the
580 // intersection of the clip and the provided rect.
581 // 4. The clear region aligns with pixel bounds
582 // 5. There are no user stencil settings (and since the clip was IOR, the clip won't need
583 // to use the stencil either).
584 // If all conditions pass, the filled rect can either be a fullscreen clear (if it's big
585 // enough), or the rectangle geometry will be used as the scissor clip on the clear.
586 // If everything passes but rule #4, this submits a simplified fill rect op instead so that the
587 // rounding differences between clip and draws don't fight each other.
588 // NOTE: we route draws into clear() regardless of performColorClearsAsDraws() since the
589 // clear call is allowed to reset the oplist even when it also happens to use a GrFillRectOp.
590
591 SkPMColor4f clearColor;
592 if (paint.numCoverageFragmentProcessors() > 0 || !paint.isConstantBlendedColor(&clearColor)) {
593 return false;
594 }
595
596 const SkRect rtRect = fRenderTargetProxy->getBoundsRect();
597 // Will be the intersection of render target, clip, and quad
598 SkRect combinedRect = rtRect;
599
600 SkRRect clipRRect;
601 GrAA clipAA;
602 if (!clip.quickContains(rtRect)) {
603 // If the clip is an rrect with no rounding, then it can replace the full RT bounds as the
604 // limiting region, although we will have to worry about AA. If the clip is anything
605 // more complicated, just punt to the regular fill rect op.
606 if (!clip.isRRect(rtRect, &clipRRect, &clipAA) || !clipRRect.isRect()) {
607 return false;
608 }
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400609
Michael Ludwig43252702019-05-16 15:04:36 -0400610 combinedRect = clipRRect.rect();
Michael Ludwig61a16512019-01-15 11:15:13 -0500611 } else {
612 // The clip is outside the render target, so the clip can be ignored
613 clipAA = GrAA::kNo;
614 }
615
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400616 GrQuadAAFlags edgeFlags; // To account for clip and draw mixing AA modes
Michael Ludwig61a16512019-01-15 11:15:13 -0500617 if (viewMatrix.rectStaysRect()) {
618 // Skip the extra overhead of inverting the view matrix to see if rtRect is contained in the
619 // drawn rectangle, and instead just intersect rtRect with the transformed rect. It will be
620 // the new clear region.
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400621 SkRect drawRect = viewMatrix.mapRect(rect);
622 if (!combinedRect.intersect(drawRect)) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500623 // No intersection means nothing should be drawn, so return true but don't add an op
624 return true;
625 }
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400626
627 // In this case, edge flags start based on draw's AA and then switch per-edge to the clip's
628 // AA setting if that edge was inset.
629 edgeFlags = aa == GrAA::kNo ? GrQuadAAFlags::kNone : GrQuadAAFlags::kAll;
630 if (combinedRect.fLeft > drawRect.fLeft) {
631 edgeFlags = set_edge_flag(edgeFlags, GrQuadAAFlags::kLeft, clipAA);
632 }
633 if (combinedRect.fTop > drawRect.fTop) {
634 edgeFlags = set_edge_flag(edgeFlags, GrQuadAAFlags::kTop, clipAA);
635 }
636 if (combinedRect.fRight < drawRect.fRight) {
637 edgeFlags = set_edge_flag(edgeFlags, GrQuadAAFlags::kRight, clipAA);
638 }
639 if (combinedRect.fBottom < drawRect.fBottom) {
640 edgeFlags = set_edge_flag(edgeFlags, GrQuadAAFlags::kBottom, clipAA);
641 }
Michael Ludwig61a16512019-01-15 11:15:13 -0500642 } else {
643 // If the transformed rectangle does not contain the combined rt and clip, the draw is too
644 // complex to be implemented as a clear
645 SkMatrix invM;
646 if (!viewMatrix.invert(&invM)) {
647 return false;
648 }
649 // The clip region in the rect's local space, so the test becomes the local rect containing
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400650 // the quad's points. If clip is non-AA, test rounded out region to avoid the scenario where
651 // the draw contains the unrounded non-aa clip, but does not contain the rounded version. Be
652 // conservative since we don't know how the GPU would round.
653 SkRect conservative;
654 if (clipAA == GrAA::kNo) {
655 conservative = SkRect::Make(combinedRect.roundOut());
656 } else {
657 conservative = combinedRect;
658 }
659 GrQuad quad = GrQuad::MakeFromRect(conservative, invM);
Michael Ludwig61a16512019-01-15 11:15:13 -0500660 if (!rect_contains_inclusive(rect, quad.point(0)) ||
661 !rect_contains_inclusive(rect, quad.point(1)) ||
662 !rect_contains_inclusive(rect, quad.point(2)) ||
663 !rect_contains_inclusive(rect, quad.point(3))) {
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400664 // No containment, so combinedRect can't be filled by a solid color
Michael Ludwig61a16512019-01-15 11:15:13 -0500665 return false;
666 }
667 // combinedRect can be filled by a solid color but doesn't need to be modified since it's
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400668 // inside the quad to be drawn, which also means the edge AA flags respect the clip AA
669 edgeFlags = clipAA == GrAA::kNo ? GrQuadAAFlags::kNone : GrQuadAAFlags::kAll;
Michael Ludwig61a16512019-01-15 11:15:13 -0500670 }
671
672 // Almost every condition is met; now it requires that the combined rect align with pixel
673 // boundaries in order for it to become a scissor-clear. Ignore the AA status in this case
674 // since non-AA with partial-pixel coordinates can be rounded differently on the GPU,
675 // leading to unexpected differences between a scissor test and a rasterized quad.
676 // Also skip very small rectangles since the scissor+clear doesn't by us much then.
677 if (combinedRect.contains(rtRect)) {
678 // Full screen clear
679 this->clear(nullptr, clearColor, CanClearFullscreen::kYes);
680 return true;
681 } else if (GrClip::IsPixelAligned(combinedRect) &&
682 combinedRect.width() > 256 && combinedRect.height() > 256) {
683 // Scissor + clear (round shouldn't do anything since we are pixel aligned)
684 SkIRect scissorRect;
685 combinedRect.round(&scissorRect);
686 this->clear(&scissorRect, clearColor, CanClearFullscreen::kNo);
687 return true;
688 }
689
690 // If we got here, we can't use a scissor + clear, but combinedRect represents the correct
691 // geometry combination of quad + clip so we can perform a simplified fill rect op. We do this
692 // mostly to avoid mismatches in rounding logic on the CPU vs. the GPU, which frequently appears
693 // when drawing and clipping something to the same non-AA rect that never-the-less has
694 // non-integer coordinates.
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400695 aa = edgeFlags == GrQuadAAFlags::kNone ? GrAA::kNo : GrAA::kYes;
Chris Dalton7d6748e2019-03-13 00:34:52 -0600696 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig61a16512019-01-15 11:15:13 -0500697 this->addDrawOp(GrFixedClip::Disabled(),
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400698 GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400699 GrQuad(combinedRect), GrQuad(combinedRect)));
Michael Ludwig61a16512019-01-15 11:15:13 -0500700 return true;
701}
702
703void GrRenderTargetContext::drawFilledRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -0500704 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500705 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -0400706 const SkMatrix& viewMatrix,
707 const SkRect& rect,
708 const GrUserStencilSettings* ss) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500709
710 if (!ss) {
711 if (this->drawFilledRectAsClear(clip, std::move(paint), aa, viewMatrix, rect)) {
712 return;
713 }
714 // Fall through to fill rect op
715 assert_alive(paint);
716 }
717
csmartdalton97f6cd52016-07-13 13:37:08 -0700718 SkRect croppedRect = rect;
Robert Phillips784b7bf2016-12-09 13:35:02 -0500719 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500720 // The rectangle would not be drawn, so no need to add a draw op to the list
721 return;
csmartdalton97f6cd52016-07-13 13:37:08 -0700722 }
robertphillips44302392016-07-08 14:43:03 -0700723
Chris Dalton7d6748e2019-03-13 00:34:52 -0600724 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400725 GrQuadAAFlags edgeFlags = aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
726 this->addDrawOp(clip,
727 GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400728 GrQuad::MakeFromRect(croppedRect, viewMatrix),
729 GrQuad(croppedRect), ss));
robertphillips391395d2016-03-02 09:26:36 -0800730}
731
Brian Osman11052242016-10-27 14:47:55 -0400732void GrRenderTargetContext::drawRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -0500733 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500734 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -0400735 const SkMatrix& viewMatrix,
736 const SkRect& rect,
737 const GrStyle* style) {
bsalomon6663acf2016-05-10 09:14:17 -0700738 if (!style) {
739 style = &GrStyle::SimpleFill();
740 }
joshualitt1de610a2016-01-06 08:26:09 -0800741 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700742 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700743 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400744 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRect", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -0700745
bsalomon6663acf2016-05-10 09:14:17 -0700746 // Path effects should've been devolved to a path in SkGpuDevice
747 SkASSERT(!style->pathEffect());
robertphillipsea461502015-05-26 11:38:03 -0700748
Robert Phillips72152832017-01-25 17:31:35 -0500749 AutoCheckFlush acf(this->drawingManager());
robertphillipsea461502015-05-26 11:38:03 -0700750
bsalomon6663acf2016-05-10 09:14:17 -0700751 const SkStrokeRec& stroke = style->strokeRec();
Robert Phillips8c8b0462018-08-24 16:18:03 -0400752 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500753 this->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect);
754 return;
bsalomona7d85ba2016-07-06 11:54:59 -0700755 } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
756 stroke.getStyle() == SkStrokeRec::kHairline_Style) {
757 if ((!rect.width() || !rect.height()) &&
758 SkStrokeRec::kHairline_Style != stroke.getStyle()) {
759 SkScalar r = stroke.getWidth() / 2;
760 // TODO: Move these stroke->fill fallbacks to GrShape?
761 switch (stroke.getJoin()) {
762 case SkPaint::kMiter_Join:
Brian Salomon82f44312017-01-11 13:42:54 -0500763 this->drawRect(
764 clip, std::move(paint), aa, viewMatrix,
765 {rect.fLeft - r, rect.fTop - r, rect.fRight + r, rect.fBottom + r},
766 &GrStyle::SimpleFill());
bsalomona7d85ba2016-07-06 11:54:59 -0700767 return;
768 case SkPaint::kRound_Join:
769 // Raster draws nothing when both dimensions are empty.
770 if (rect.width() || rect.height()){
771 SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r);
Brian Salomon82f44312017-01-11 13:42:54 -0500772 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect,
773 GrStyle::SimpleFill());
bsalomona7d85ba2016-07-06 11:54:59 -0700774 return;
775 }
776 case SkPaint::kBevel_Join:
777 if (!rect.width()) {
Brian Salomon82f44312017-01-11 13:42:54 -0500778 this->drawRect(clip, std::move(paint), aa, viewMatrix,
bsalomona7d85ba2016-07-06 11:54:59 -0700779 {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom},
780 &GrStyle::SimpleFill());
781 } else {
Brian Salomon82f44312017-01-11 13:42:54 -0500782 this->drawRect(clip, std::move(paint), aa, viewMatrix,
bsalomona7d85ba2016-07-06 11:54:59 -0700783 {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r},
784 &GrStyle::SimpleFill());
785 }
786 return;
787 }
788 }
robertphillips44302392016-07-08 14:43:03 -0700789
Brian Salomonbaaf4392017-06-15 09:59:23 -0400790 std::unique_ptr<GrDrawOp> op;
robertphillips44302392016-07-08 14:43:03 -0700791
Chris Dalton7d6748e2019-03-13 00:34:52 -0600792 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500793 op = GrStrokeRectOp::Make(fContext, std::move(paint), aaType, viewMatrix, rect, stroke);
794 // op may be null if the stroke is not supported or if using coverage aa and the view matrix
795 // does not preserve rectangles.
Brian Salomon42521e82016-12-07 16:44:58 -0500796 if (op) {
Brian Salomonbaaf4392017-06-15 09:59:23 -0400797 this->addDrawOp(clip, std::move(op));
robertphillips44302392016-07-08 14:43:03 -0700798 return;
robertphillips4bc31812016-03-01 12:22:49 -0800799 }
robertphillips4bc31812016-03-01 12:22:49 -0800800 }
Mike Klein16885072018-12-11 09:54:31 -0500801 assert_alive(paint);
Brian Salomon2fad74a2017-12-20 13:28:55 -0500802 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(rect, *style));
robertphillipsea461502015-05-26 11:38:03 -0700803}
804
Michael Ludwig69858532018-11-28 15:34:34 -0500805void GrRenderTargetContext::drawQuadSet(const GrClip& clip, GrPaint&& paint, GrAA aa,
806 const SkMatrix& viewMatrix, const QuadSetEntry quads[],
807 int cnt) {
Chris Dalton7d6748e2019-03-13 00:34:52 -0600808 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig69858532018-11-28 15:34:34 -0500809 this->addDrawOp(clip, GrFillRectOp::MakeSet(fContext, std::move(paint), aaType, viewMatrix,
810 quads, cnt));
811}
812
Robert Phillipsec2249f2016-11-09 08:54:35 -0500813int GrRenderTargetContextPriv::maxWindowRectangles() const {
814 return fRenderTargetContext->fRenderTargetProxy->maxWindowRectangles(
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400815 *fRenderTargetContext->caps());
Robert Phillipsec2249f2016-11-09 08:54:35 -0500816}
817
Jim Van Verth6a40abc2017-11-02 16:56:09 +0000818void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
robertphillips976f5f02016-06-03 10:59:20 -0700819 ASSERT_SINGLE_OWNER_PRIV
820 RETURN_IF_ABANDONED_PRIV
Brian Osman11052242016-10-27 14:47:55 -0400821 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400822 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clearStencilClip",
823 fRenderTargetContext->fContext);
robertphillips976f5f02016-06-03 10:59:20 -0700824
Robert Phillips72152832017-01-25 17:31:35 -0500825 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
Robert Phillipsb9a02a12017-04-06 11:08:40 -0400826
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500827 fRenderTargetContext->internalStencilClear(clip, insideStencilMask);
828}
829
830void GrRenderTargetContext::internalStencilClear(const GrFixedClip& clip, bool insideStencilMask) {
831 if (this->caps()->performStencilClearsAsDraws()) {
832 const GrUserStencilSettings* ss = GrStencilSettings::SetClipBitSettings(insideStencilMask);
833 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
834
835 // Configure the paint to have no impact on the color buffer
836 GrPaint paint;
Michael Ludwig0cb2fde2019-05-28 13:14:41 -0400837 paint.setXPFactory(GrDisableColorXPFactory::Get());
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500838
Michael Ludwig6e17f1d2019-05-15 14:00:20 +0000839 // Mark stencil usage here before addDrawOp() so that it doesn't try to re-call
840 // internalStencilClear() just because the op has stencil settings.
841 this->setNeedsStencil();
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400842 this->addDrawOp(clip, GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
843 rtRect, ss));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500844 } else {
845 std::unique_ptr<GrOp> op(GrClearStencilClipOp::Make(fContext, clip, insideStencilMask,
846 fRenderTargetProxy.get()));
847 if (!op) {
848 return;
849 }
850 this->getRTOpList()->addOp(std::move(op), *this->caps());
Robert Phillipse60ad622016-11-17 10:22:48 -0500851 }
robertphillips976f5f02016-06-03 10:59:20 -0700852}
853
Chris Daltonbbfd5162017-11-07 13:35:22 -0700854void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
Chris Dalton09e56892019-03-13 00:22:01 -0600855 GrAA doStencilMSAA,
Brian Osman11052242016-10-27 14:47:55 -0400856 const SkMatrix& viewMatrix,
857 const GrPath* path) {
Brian Salomon467921e2017-03-06 16:17:12 -0500858 ASSERT_SINGLE_OWNER_PRIV
859 RETURN_IF_ABANDONED_PRIV
860 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400861 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilPath",
862 fRenderTargetContext->fContext);
Brian Salomon467921e2017-03-06 16:17:12 -0500863
Brian Salomon467921e2017-03-06 16:17:12 -0500864 // TODO: extract portions of checkDraw that are relevant to path stenciling.
865 SkASSERT(path);
866 SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport());
867
868 // FIXME: Use path bounds instead of this WAR once
869 // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
870 SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height());
871
872 // Setup clip
Chris Daltonbbfd5162017-11-07 13:35:22 -0700873 GrAppliedHardClip appliedClip;
874 if (!clip.apply(fRenderTargetContext->width(), fRenderTargetContext->height(), &appliedClip,
875 &bounds)) {
Brian Salomon467921e2017-03-06 16:17:12 -0500876 return;
877 }
878
Michael Ludwig6e17f1d2019-05-15 14:00:20 +0000879 fRenderTargetContext->setNeedsStencil();
880
Robert Phillips7c525e62018-06-12 10:11:12 -0400881 std::unique_ptr<GrOp> op = GrStencilPathOp::Make(fRenderTargetContext->fContext,
882 viewMatrix,
Chris Dalton09e56892019-03-13 00:22:01 -0600883 GrAA::kYes == doStencilMSAA,
Brian Salomon467921e2017-03-06 16:17:12 -0500884 path->getFillType(),
885 appliedClip.hasStencilClip(),
Brian Salomon467921e2017-03-06 16:17:12 -0500886 appliedClip.scissorState(),
Brian Salomon467921e2017-03-06 16:17:12 -0500887 path);
Robert Phillipsb9a02a12017-04-06 11:08:40 -0400888 if (!op) {
889 return;
890 }
Brian Salomon97180af2017-03-14 13:42:58 -0400891 op->setClippedBounds(bounds);
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400892 fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
robertphillips976f5f02016-06-03 10:59:20 -0700893}
894
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400895void GrRenderTargetContextPriv::stencilRect(const GrClip& clip,
Brian Osman11052242016-10-27 14:47:55 -0400896 const GrUserStencilSettings* ss,
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400897 GrPaint&& paint,
Chris Dalton09e56892019-03-13 00:22:01 -0600898 GrAA doStencilMSAA,
Brian Osman11052242016-10-27 14:47:55 -0400899 const SkMatrix& viewMatrix,
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400900 const SkRect& rect,
901 const SkMatrix* localMatrix) {
robertphillips976f5f02016-06-03 10:59:20 -0700902 ASSERT_SINGLE_OWNER_PRIV
903 RETURN_IF_ABANDONED_PRIV
Brian Osman11052242016-10-27 14:47:55 -0400904 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400905 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilRect",
906 fRenderTargetContext->fContext);
907
Robert Phillips72152832017-01-25 17:31:35 -0500908 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
robertphillips976f5f02016-06-03 10:59:20 -0700909
Chris Dalton09e56892019-03-13 00:22:01 -0600910 auto aaType = (GrAA::kYes == doStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400911
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400912 GrQuad localQuad = localMatrix ? GrQuad::MakeFromRect(rect, *localMatrix)
913 : GrQuad(rect);
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400914 std::unique_ptr<GrDrawOp> op = GrFillRectOp::Make(
Michael Ludwig64b28a72019-05-28 12:02:00 -0400915 fRenderTargetContext->fContext, std::move(paint), aaType, GrQuadAAFlags::kNone,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400916 GrQuad::MakeFromRect(rect, viewMatrix), localQuad, ss);
Brian Salomonbaaf4392017-06-15 09:59:23 -0400917 fRenderTargetContext->addDrawOp(clip, std::move(op));
robertphillips976f5f02016-06-03 10:59:20 -0700918}
919
Michael Ludwig136f45a2019-02-19 11:44:41 -0500920void GrRenderTargetContext::fillRectWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa,
Michael Ludwig75451902019-01-23 11:14:29 -0500921 GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix,
Michael Ludwig136f45a2019-02-19 11:44:41 -0500922 const SkRect& rect, const SkRect* localRect) {
Michael Ludwig75451902019-01-23 11:14:29 -0500923 ASSERT_SINGLE_OWNER
924 RETURN_IF_ABANDONED
925 SkDEBUGCODE(this->validate();)
926 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithEdgeAA", fContext);
927
Chris Dalton7d6748e2019-03-13 00:34:52 -0600928 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig136f45a2019-02-19 11:44:41 -0500929 std::unique_ptr<GrDrawOp> op;
Michael Ludwig75451902019-01-23 11:14:29 -0500930
Michael Ludwig136f45a2019-02-19 11:44:41 -0500931 if (localRect) {
932 // If local coordinates are provided, skip the optimization check to go through
933 // drawFilledRect, and also calculate clipped local coordinates
934 SkRect croppedRect = rect;
935 SkRect croppedLocalRect = *localRect;
936 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect,
937 &croppedLocalRect)) {
938 return;
939 }
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400940 op = GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeAA,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400941 GrQuad::MakeFromRect(croppedRect, viewMatrix),
942 GrQuad(croppedLocalRect));
Michael Ludwig136f45a2019-02-19 11:44:41 -0500943 } else {
944 // If aaType turns into MSAA, make sure to keep quads with no AA edges as MSAA. Sending
945 // those to drawFilledRect() would have it turn off MSAA in that case, which breaks seaming
946 // with any partial AA edges that kept MSAA.
947 if (aaType != GrAAType::kMSAA &&
948 (edgeAA == GrQuadAAFlags::kNone || edgeAA == GrQuadAAFlags::kAll)) {
949 // This is equivalent to a regular filled rect draw, so route through there to take
950 // advantage of draw->clear optimizations
951 this->drawFilledRect(clip, std::move(paint), GrAA(edgeAA == GrQuadAAFlags::kAll),
952 viewMatrix, rect);
953 return;
954 }
955
956 SkRect croppedRect = rect;
957 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
958 return;
959 }
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400960 op = GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeAA,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400961 GrQuad::MakeFromRect(croppedRect, viewMatrix),
962 GrQuad(croppedRect));
Michael Ludwig75451902019-01-23 11:14:29 -0500963 }
964
965 AutoCheckFlush acf(this->drawingManager());
Michael Ludwig136f45a2019-02-19 11:44:41 -0500966 this->addDrawOp(clip, std::move(op));
Michael Ludwig75451902019-01-23 11:14:29 -0500967}
968
Michael Ludwigce62dec2019-02-19 11:48:46 -0500969void GrRenderTargetContext::fillQuadWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa,
970 GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix,
971 const SkPoint quad[4], const SkPoint localQuad[4]) {
972 ASSERT_SINGLE_OWNER
973 RETURN_IF_ABANDONED
974 SkDEBUGCODE(this->validate();)
975 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillQuadWithEdgeAA", fContext);
976
Chris Dalton7d6748e2019-03-13 00:34:52 -0600977 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwigce62dec2019-02-19 11:48:46 -0500978
979 AutoCheckFlush acf(this->drawingManager());
Michael Ludwig64b28a72019-05-28 12:02:00 -0400980 const SkPoint* localPoints = localQuad ? localQuad : quad;
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400981 this->addDrawOp(clip,
982 GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeAA,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400983 GrQuad::MakeFromSkQuad(quad, viewMatrix),
984 GrQuad::MakeFromSkQuad(localPoints, SkMatrix::I())));
Michael Ludwigce62dec2019-02-19 11:48:46 -0500985}
986
Michael Ludwigd54ca8f2019-02-13 13:25:21 -0500987// Creates a paint for GrFillRectOp that matches behavior of GrTextureOp
988static void draw_texture_to_grpaint(sk_sp<GrTextureProxy> proxy, const SkRect* domain,
989 GrSamplerState::Filter filter, SkBlendMode mode,
990 const SkPMColor4f& color, sk_sp<GrColorSpaceXform> csXform,
991 GrPaint* paint) {
992 paint->setColor4f(color);
993 paint->setXPFactory(SkBlendMode_AsXPFactory(mode));
994
995 std::unique_ptr<GrFragmentProcessor> fp;
996 if (domain) {
Michael Ludwigce62dec2019-02-19 11:48:46 -0500997 SkRect correctedDomain = *domain;
998 if (filter == GrSamplerState::Filter::kBilerp) {
999 // Inset by 1/2 pixel, which GrTextureOp and GrTextureAdjuster handle automatically
1000 correctedDomain.inset(0.5f, 0.5f);
1001 }
1002 fp = GrTextureDomainEffect::Make(std::move(proxy), SkMatrix::I(), correctedDomain,
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001003 GrTextureDomain::kClamp_Mode, filter);
1004 } else {
1005 fp = GrSimpleTextureEffect::Make(std::move(proxy), SkMatrix::I(), filter);
1006 }
1007
1008 fp = GrColorSpaceXformEffect::Make(std::move(fp), csXform);
1009 paint->addColorFragmentProcessor(std::move(fp));
1010}
1011
Brian Salomonbe3c1d22018-05-21 12:54:39 -04001012void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001013 GrSamplerState::Filter filter, SkBlendMode mode,
1014 const SkPMColor4f& color, const SkRect& srcRect,
Michael Ludwig136f45a2019-02-19 11:44:41 -05001015 const SkRect& dstRect, GrAA aa, GrQuadAAFlags aaFlags,
Brian Salomonb80ffee2018-05-23 16:39:39 -04001016 SkCanvas::SrcRectConstraint constraint,
Brian Salomonbe3c1d22018-05-21 12:54:39 -04001017 const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -05001018 sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
Brian Salomon34169692017-08-28 15:32:01 -04001019 ASSERT_SINGLE_OWNER
1020 RETURN_IF_ABANDONED
1021 SkDEBUGCODE(this->validate();)
Brian Salomonbe3c1d22018-05-21 12:54:39 -04001022 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTexture", fContext);
Brian Salomonf1709042018-10-03 11:57:00 -04001023 if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
1024 srcRect.contains(proxy->getWorstCaseBoundsRect())) {
1025 constraint = SkCanvas::kFast_SrcRectConstraint;
Brian Salomon34169692017-08-28 15:32:01 -04001026 }
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001027
Chris Dalton7d6748e2019-03-13 00:34:52 -06001028 GrAAType aaType = this->chooseAAType(aa);
Brian Salomonff9d6d32017-08-30 10:27:49 -04001029 SkRect clippedDstRect = dstRect;
1030 SkRect clippedSrcRect = srcRect;
1031 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &clippedDstRect,
1032 &clippedSrcRect)) {
1033 return;
1034 }
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001035
1036 AutoCheckFlush acf(this->drawingManager());
1037
1038 std::unique_ptr<GrDrawOp> op;
1039 if (mode != SkBlendMode::kSrcOver) {
1040 // Emulation mode with GrPaint and GrFillRectOp
1041 if (filter != GrSamplerState::Filter::kNearest &&
1042 !GrTextureOp::GetFilterHasEffect(viewMatrix, clippedSrcRect, clippedDstRect)) {
1043 filter = GrSamplerState::Filter::kNearest;
1044 }
1045
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001046 GrPaint paint;
1047 draw_texture_to_grpaint(std::move(proxy),
Michael Ludwigce62dec2019-02-19 11:48:46 -05001048 constraint == SkCanvas::kStrict_SrcRectConstraint ? &srcRect : nullptr,
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001049 filter, mode, color, std::move(textureColorSpaceXform), &paint);
Michael Ludwig4a0cf502019-05-30 12:54:09 -04001050 op = GrFillRectOp::Make(fContext, std::move(paint), aaType, aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -04001051 GrQuad::MakeFromRect(clippedDstRect, viewMatrix),
1052 GrQuad(clippedSrcRect));
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001053 } else {
1054 // Can use a lighter weight op that can chain across proxies
1055 op = GrTextureOp::Make(fContext, std::move(proxy), filter, color, clippedSrcRect,
1056 clippedDstRect, aaType, aaFlags, constraint, viewMatrix,
1057 std::move(textureColorSpaceXform));
1058 }
1059
Brian Salomon2213ee92018-10-02 10:44:21 -04001060 this->addDrawOp(clip, std::move(op));
Brian Salomon34169692017-08-28 15:32:01 -04001061}
1062
Michael Ludwigce62dec2019-02-19 11:48:46 -05001063void GrRenderTargetContext::drawTextureQuad(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
1064 GrSamplerState::Filter filter, SkBlendMode mode,
1065 const SkPMColor4f& color, const SkPoint srcQuad[4],
1066 const SkPoint dstQuad[4], GrAA aa,
1067 GrQuadAAFlags aaFlags, const SkRect* domain,
1068 const SkMatrix& viewMatrix,
1069 sk_sp<GrColorSpaceXform> texXform) {
1070 ASSERT_SINGLE_OWNER
1071 RETURN_IF_ABANDONED
1072 SkDEBUGCODE(this->validate();)
1073 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureQuad", fContext);
1074 if (domain && domain->contains(proxy->getWorstCaseBoundsRect())) {
1075 domain = nullptr;
1076 }
1077
Chris Dalton7d6748e2019-03-13 00:34:52 -06001078 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwigce62dec2019-02-19 11:48:46 -05001079
1080 // Unlike drawTexture(), don't bother cropping or optimizing the filter type since we're
1081 // sampling an arbitrary quad of the texture.
1082 AutoCheckFlush acf(this->drawingManager());
1083 std::unique_ptr<GrDrawOp> op;
1084 if (mode != SkBlendMode::kSrcOver) {
1085 // Emulation mode, but don't bother converting to kNearest filter since it's an arbitrary
1086 // quad that is being drawn, which makes the tests too expensive here
1087 GrPaint paint;
1088 draw_texture_to_grpaint(
1089 std::move(proxy), domain, filter, mode, color, std::move(texXform), &paint);
Michael Ludwig4a0cf502019-05-30 12:54:09 -04001090 op = GrFillRectOp::Make(fContext, std::move(paint), aaType, aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -04001091 GrQuad::MakeFromSkQuad(dstQuad, viewMatrix),
1092 GrQuad::MakeFromSkQuad(srcQuad, SkMatrix::I()));
Michael Ludwigce62dec2019-02-19 11:48:46 -05001093 } else {
1094 // Use lighter weight GrTextureOp
1095 op = GrTextureOp::MakeQuad(fContext, std::move(proxy), filter, color, srcQuad, dstQuad,
1096 aaType, aaFlags, domain, viewMatrix, std::move(texXform));
1097 }
1098
1099 this->addDrawOp(clip, std::move(op));
1100}
1101
Brian Salomond7065e72018-10-12 11:42:02 -04001102void GrRenderTargetContext::drawTextureSet(const GrClip& clip, const TextureSetEntry set[], int cnt,
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001103 GrSamplerState::Filter filter, SkBlendMode mode,
Michael Ludwig31ba7182019-04-03 10:38:06 -04001104 GrAA aa, SkCanvas::SrcRectConstraint constraint,
1105 const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -05001106 sk_sp<GrColorSpaceXform> texXform) {
Brian Salomond7065e72018-10-12 11:42:02 -04001107 ASSERT_SINGLE_OWNER
1108 RETURN_IF_ABANDONED
1109 SkDEBUGCODE(this->validate();)
1110 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureSet", fContext);
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001111
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001112 if (mode != SkBlendMode::kSrcOver ||
Robert Phillips9da87e02019-02-04 13:26:26 -05001113 !fContext->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001114 // Draw one at a time with GrFillRectOp and a GrPaint that emulates what GrTextureOp does
Michael Ludwig7ae2ab52019-03-05 16:00:20 -05001115 SkMatrix ctm;
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001116 for (int i = 0; i < cnt; ++i) {
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001117 float alpha = set[i].fAlpha;
Michael Ludwig7ae2ab52019-03-05 16:00:20 -05001118 ctm = viewMatrix;
1119 if (set[i].fPreViewMatrix) {
1120 ctm.preConcat(*set[i].fPreViewMatrix);
1121 }
1122
Michael Ludwig1433cfd2019-02-27 17:12:30 -05001123 if (set[i].fDstClipQuad == nullptr) {
Michael Ludwigce62dec2019-02-19 11:48:46 -05001124 // Stick with original rectangles, which allows the ops to know more about what's
1125 // being drawn.
1126 this->drawTexture(clip, set[i].fProxy, filter, mode, {alpha, alpha, alpha, alpha},
1127 set[i].fSrcRect, set[i].fDstRect, aa, set[i].fAAFlags,
Michael Ludwig31ba7182019-04-03 10:38:06 -04001128 constraint, ctm, texXform);
Michael Ludwigce62dec2019-02-19 11:48:46 -05001129 } else {
1130 // Generate interpolated texture coordinates to match the dst clip
1131 SkPoint srcQuad[4];
Michael Ludwig1433cfd2019-02-27 17:12:30 -05001132 GrMapRectPoints(set[i].fDstRect, set[i].fSrcRect, set[i].fDstClipQuad, srcQuad, 4);
Michael Ludwig31ba7182019-04-03 10:38:06 -04001133 const SkRect* domain = constraint == SkCanvas::kStrict_SrcRectConstraint
1134 ? &set[i].fSrcRect : nullptr;
Michael Ludwigce62dec2019-02-19 11:48:46 -05001135 this->drawTextureQuad(clip, set[i].fProxy, filter, mode,
Michael Ludwig1433cfd2019-02-27 17:12:30 -05001136 {alpha, alpha, alpha, alpha}, srcQuad, set[i].fDstClipQuad,
Michael Ludwig31ba7182019-04-03 10:38:06 -04001137 aa, set[i].fAAFlags, domain, ctm, texXform);
Michael Ludwigce62dec2019-02-19 11:48:46 -05001138 }
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001139 }
1140 } else {
1141 // Can use a single op, avoiding GrPaint creation, and can batch across proxies
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001142 AutoCheckFlush acf(this->drawingManager());
Chris Dalton7d6748e2019-03-13 00:34:52 -06001143 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig31ba7182019-04-03 10:38:06 -04001144 auto op = GrTextureOp::MakeSet(fContext, set, cnt, filter, aaType, constraint, viewMatrix,
Michael Ludwig009b92e2019-02-15 16:03:53 -05001145 std::move(texXform));
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001146 this->addDrawOp(clip, std::move(op));
1147 }
Brian Salomond7065e72018-10-12 11:42:02 -04001148}
1149
Brian Osman11052242016-10-27 14:47:55 -04001150void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001151 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001152 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001153 const SkMatrix& viewMatrix,
1154 const SkRect& rectToDraw,
1155 const SkMatrix& localMatrix) {
joshualitt1de610a2016-01-06 08:26:09 -08001156 ASSERT_SINGLE_OWNER
joshualittb6b513b2015-08-21 10:25:18 -07001157 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07001158 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001159 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithLocalMatrix", fContext);
joshualittb6b513b2015-08-21 10:25:18 -07001160
csmartdalton97f6cd52016-07-13 13:37:08 -07001161 SkRect croppedRect = rectToDraw;
robertphillips13a7eee2016-08-31 15:06:24 -07001162 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
csmartdalton97f6cd52016-07-13 13:37:08 -07001163 return;
1164 }
1165
Robert Phillips72152832017-01-25 17:31:35 -05001166 AutoCheckFlush acf(this->drawingManager());
csmartdaltona7f29642016-07-07 08:49:11 -07001167
Chris Dalton7d6748e2019-03-13 00:34:52 -06001168 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig4a0cf502019-05-30 12:54:09 -04001169 GrQuadAAFlags edgeFlags = aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
1170 this->addDrawOp(clip,
1171 GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -04001172 GrQuad::MakeFromRect(croppedRect, viewMatrix),
1173 GrQuad::MakeFromRect(croppedRect, localMatrix)));
robertphillipsea461502015-05-26 11:38:03 -07001174}
1175
Brian Osman11052242016-10-27 14:47:55 -04001176void GrRenderTargetContext::drawVertices(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001177 GrPaint&& paint,
Brian Osman11052242016-10-27 14:47:55 -04001178 const SkMatrix& viewMatrix,
Brian Osmanae0c50c2017-05-25 16:56:34 -04001179 sk_sp<SkVertices> vertices,
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001180 const SkVertices::Bone bones[],
Ruiqi Mao4ec72f72018-07-10 17:21:07 -04001181 int boneCount,
Brian Osmanae0c50c2017-05-25 16:56:34 -04001182 GrPrimitiveType* overridePrimType) {
Brian Salomon199fb872017-02-06 09:41:10 -05001183 ASSERT_SINGLE_OWNER
1184 RETURN_IF_ABANDONED
1185 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001186 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawVertices", fContext);
Brian Salomon199fb872017-02-06 09:41:10 -05001187
1188 AutoCheckFlush acf(this->drawingManager());
1189
1190 SkASSERT(vertices);
Chris Dalton7d6748e2019-03-13 00:34:52 -06001191 GrAAType aaType = this->chooseAAType(GrAA::kNo);
Brian Salomonf3569f02017-10-24 12:52:33 -04001192 std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make(
Ruiqi Mao4ec72f72018-07-10 17:21:07 -04001193 fContext, std::move(paint), std::move(vertices), bones, boneCount, viewMatrix, aaType,
Brian Salomonf3569f02017-10-24 12:52:33 -04001194 this->colorSpaceInfo().refColorSpaceXformFromSRGB(), overridePrimType);
Brian Salomonc2f42542017-07-12 14:11:22 -04001195 this->addDrawOp(clip, std::move(op));
robertphillipsea461502015-05-26 11:38:03 -07001196}
1197
1198///////////////////////////////////////////////////////////////////////////////
1199
Brian Osman4d92b892019-03-24 00:53:23 +00001200void GrRenderTargetContext::drawAtlas(const GrClip& clip,
1201 GrPaint&& paint,
1202 const SkMatrix& viewMatrix,
1203 int spriteCount,
1204 const SkRSXform xform[],
1205 const SkRect texRect[],
1206 const SkColor colors[]) {
1207 ASSERT_SINGLE_OWNER
1208 RETURN_IF_ABANDONED
1209 SkDEBUGCODE(this->validate();)
1210 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawAtlas", fContext);
1211
1212 AutoCheckFlush acf(this->drawingManager());
1213
1214 GrAAType aaType = this->chooseAAType(GrAA::kNo);
1215 std::unique_ptr<GrDrawOp> op = GrDrawAtlasOp::Make(fContext, std::move(paint), viewMatrix,
1216 aaType, spriteCount, xform, texRect, colors);
1217 this->addDrawOp(clip, std::move(op));
1218}
1219
1220///////////////////////////////////////////////////////////////////////////////
1221
Brian Osman11052242016-10-27 14:47:55 -04001222void GrRenderTargetContext::drawRRect(const GrClip& origClip,
Brian Salomon82f44312017-01-11 13:42:54 -05001223 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001224 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001225 const SkMatrix& viewMatrix,
1226 const SkRRect& rrect,
1227 const GrStyle& style) {
joshualitt1de610a2016-01-06 08:26:09 -08001228 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07001229 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07001230 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001231 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRRect", fContext);
Robert Phillips85290802018-07-02 13:14:28 -04001232
1233 const SkStrokeRec& stroke = style.strokeRec();
1234 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.isEmpty()) {
robertphillipsea461502015-05-26 11:38:03 -07001235 return;
1236 }
1237
bsalomon7f0d9f32016-08-15 14:49:10 -07001238 GrNoClip noclip;
1239 const GrClip* clip = &origClip;
1240#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1241 // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
Brian Salomon42521e82016-12-07 16:44:58 -05001242 // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it
bsalomon7f0d9f32016-08-15 14:49:10 -07001243 // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
1244 // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
Michael Ludwig28398842019-03-25 10:24:24 -04001245 // can be ignored. We'd prefer to fix this in the framework by removing the clips calls. This
1246 // only works for filled rrects since the stroke width outsets beyond the rrect itself.
bsalomon7f0d9f32016-08-15 14:49:10 -07001247 SkRRect devRRect;
Michael Ludwig28398842019-03-25 10:24:24 -04001248 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.transform(viewMatrix, &devRRect) &&
1249 clip->quickContains(devRRect)) {
bsalomon7f0d9f32016-08-15 14:49:10 -07001250 clip = &noclip;
1251 }
1252#endif
bsalomon6663acf2016-05-10 09:14:17 -07001253 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
ksakamotoec7f2ac2016-07-05 03:54:53 -07001254
Robert Phillips72152832017-01-25 17:31:35 -05001255 AutoCheckFlush acf(this->drawingManager());
csmartdaltona7f29642016-07-07 08:49:11 -07001256
Chris Dalton7d6748e2019-03-13 00:34:52 -06001257 GrAAType aaType = this->chooseAAType(aa);
Chris Dalton133944a2018-11-16 23:30:29 -05001258
Chris Dalton0dffbab2019-03-27 13:08:50 -06001259 std::unique_ptr<GrDrawOp> op;
1260 if (style.isSimpleFill()) {
1261 assert_alive(paint);
1262 op = GrFillRRectOp::Make(
1263 fContext, aaType, viewMatrix, rrect, *this->caps(), std::move(paint));
1264 }
Greg Daniel2655ede2019-04-10 00:49:28 +00001265 if (!op && GrAAType::kCoverage == aaType) {
Chris Dalton0dffbab2019-03-27 13:08:50 -06001266 assert_alive(paint);
1267 op = GrOvalOpFactory::MakeRRectOp(
Greg Daniel2655ede2019-04-10 00:49:28 +00001268 fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
1269
Chris Dalton0dffbab2019-03-27 13:08:50 -06001270 }
1271 if (op) {
1272 this->addDrawOp(*clip, std::move(op));
1273 return;
robertphillipsea461502015-05-26 11:38:03 -07001274 }
robertphillipsb56f9272016-02-25 11:03:52 -08001275
Mike Klein16885072018-12-11 09:54:31 -05001276 assert_alive(paint);
Brian Salomon2fad74a2017-12-20 13:28:55 -05001277 this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix,
1278 GrShape(rrect, style));
robertphillipsea461502015-05-26 11:38:03 -07001279}
1280
Jim Van Verthc5903412016-11-17 15:27:09 -05001281///////////////////////////////////////////////////////////////////////////////
1282
Jim Van Verth3af1af92017-05-18 15:06:54 -04001283static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
1284 SkPoint3 result;
1285 m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
1286 result.fZ = pt.fZ;
1287 return result;
1288}
1289
1290bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
Jim Van Verth3af1af92017-05-18 15:06:54 -04001291 const SkMatrix& viewMatrix,
1292 const SkPath& path,
1293 const SkDrawShadowRec& rec) {
Jim Van Verthc5903412016-11-17 15:27:09 -05001294 ASSERT_SINGLE_OWNER
Robert Phillips6a6de562019-02-15 15:19:15 -05001295 if (fContext->priv().abandoned()) {
Jim Van Verth3af1af92017-05-18 15:06:54 -04001296 return true;
1297 }
Jim Van Verthc5903412016-11-17 15:27:09 -05001298 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001299 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFastShadow", fContext);
Jim Van Verth3af1af92017-05-18 15:06:54 -04001300
1301 // check z plane
1302 bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
1303 !SkScalarNearlyZero(rec.fZPlaneParams.fY));
1304 bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1305 if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
1306 return false;
1307 }
1308
1309 SkRRect rrect;
1310 SkRect rect;
1311 // we can only handle rects, circles, and rrects with circular corners
Mike Reed242135a2018-02-22 13:41:39 -05001312 bool isRRect = path.isRRect(&rrect) && SkRRectPriv::IsSimpleCircular(rrect) &&
Jim Van Verth3af1af92017-05-18 15:06:54 -04001313 rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero;
1314 if (!isRRect &&
1315 path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
1316 rect.width() > SK_ScalarNearlyZero) {
1317 rrect.setOval(rect);
1318 isRRect = true;
1319 }
1320 if (!isRRect && path.isRect(&rect)) {
1321 rrect.setRect(rect);
1322 isRRect = true;
1323 }
1324
1325 if (!isRRect) {
1326 return false;
1327 }
1328
Jim Van Verthc5903412016-11-17 15:27:09 -05001329 if (rrect.isEmpty()) {
Jim Van Verth3af1af92017-05-18 15:06:54 -04001330 return true;
Jim Van Verthc5903412016-11-17 15:27:09 -05001331 }
1332
Robert Phillips72152832017-01-25 17:31:35 -05001333 AutoCheckFlush acf(this->drawingManager());
Jim Van Verthc5903412016-11-17 15:27:09 -05001334
Jim Van Verth3af1af92017-05-18 15:06:54 -04001335 // transform light
1336 SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
1337
1338 // 1/scale
1339 SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1340 SkScalarInvert(viewMatrix[SkMatrix::kMScaleX]) :
1341 sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1342 viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1343
1344 SkScalar occluderHeight = rec.fZPlaneParams.fZ;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001345 bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1346
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001347 if (SkColorGetA(rec.fAmbientColor) > 0) {
Jim Van Verth1af03d42017-07-31 09:34:58 -04001348 SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
1349 const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
1350 const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001351
1352 // Outset the shadow rrect to the border of the penumbra
1353 SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1354 SkRRect ambientRRect;
1355 SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1356 // If the rrect was an oval then its outset will also be one.
1357 // We set it explicitly to avoid errors.
1358 if (rrect.isOval()) {
1359 ambientRRect = SkRRect::MakeOval(outsetRect);
1360 } else {
Mike Reed242135a2018-02-22 13:41:39 -05001361 SkScalar outsetRad = SkRRectPriv::GetSimpleRadii(rrect).fX + ambientPathOutset;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001362 ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1363 }
1364
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001365 GrColor ambientColor = SkColorToPremulGrColor(rec.fAmbientColor);
Jim Van Verth3af1af92017-05-18 15:06:54 -04001366 if (transparent) {
1367 // set a large inset to force a fill
1368 devSpaceInsetWidth = ambientRRect.width();
1369 }
Jim Van Verth39e71652018-04-23 18:08:45 +00001370
Robert Phillips7c525e62018-06-12 10:11:12 -04001371 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1372 ambientColor,
1373 viewMatrix,
Brian Salomon05969092017-07-13 11:20:51 -04001374 ambientRRect,
1375 devSpaceAmbientBlur,
Jim Van Verthfb186392018-09-11 11:37:46 -04001376 devSpaceInsetWidth);
Robert Phillipse5763782019-04-17 14:38:24 -04001377 if (op) {
1378 this->addDrawOp(clip, std::move(op));
1379 }
Jim Van Verthc5903412016-11-17 15:27:09 -05001380 }
Jim Van Verth3af1af92017-05-18 15:06:54 -04001381
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001382 if (SkColorGetA(rec.fSpotColor) > 0) {
Jim Van Verth1af03d42017-07-31 09:34:58 -04001383 SkScalar devSpaceSpotBlur;
1384 SkScalar spotScale;
1385 SkVector spotOffset;
1386 SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY,
1387 devLightPos.fZ, rec.fLightRadius,
1388 &devSpaceSpotBlur, &spotScale, &spotOffset);
1389 // handle scale of radius due to CTM
Jim Van Verth3af1af92017-05-18 15:06:54 -04001390 const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1391
Jim Van Verth3af1af92017-05-18 15:06:54 -04001392 // Adjust translate for the effect of the scale.
1393 spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1394 spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1395 // This offset is in dev space, need to transform it into source space.
1396 SkMatrix ctmInverse;
1397 if (viewMatrix.invert(&ctmInverse)) {
1398 ctmInverse.mapPoints(&spotOffset, 1);
1399 } else {
1400 // Since the matrix is a similarity, this should never happen, but just in case...
1401 SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1402 SkASSERT(false);
1403 }
1404
1405 // Compute the transformed shadow rrect
1406 SkRRect spotShadowRRect;
1407 SkMatrix shadowTransform;
1408 shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1409 rrect.transform(shadowTransform, &spotShadowRRect);
Mike Reed242135a2018-02-22 13:41:39 -05001410 SkScalar spotRadius = SkRRectPriv::GetSimpleRadii(spotShadowRRect).fX;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001411
1412 // Compute the insetWidth
Jim Van Verth1af03d42017-07-31 09:34:58 -04001413 SkScalar blurOutset = srcSpaceSpotBlur;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001414 SkScalar insetWidth = blurOutset;
1415 if (transparent) {
1416 // If transparent, just do a fill
1417 insetWidth += spotShadowRRect.width();
1418 } else {
1419 // For shadows, instead of using a stroke we specify an inset from the penumbra
1420 // border. We want to extend this inset area so that it meets up with the caster
1421 // geometry. The inset geometry will by default already be inset by the blur width.
1422 //
1423 // We compare the min and max corners inset by the radius between the original
1424 // rrect and the shadow rrect. The distance between the two plus the difference
1425 // between the scaled radius and the original radius gives the distance from the
1426 // transformed shadow shape to the original shape in that corner. The max
1427 // of these gives the maximum distance we need to cover.
1428 //
1429 // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1430 // that to get the full insetWidth.
1431 SkScalar maxOffset;
1432 if (rrect.isRect()) {
1433 // Manhattan distance works better for rects
1434 maxOffset = SkTMax(SkTMax(SkTAbs(spotShadowRRect.rect().fLeft -
1435 rrect.rect().fLeft),
1436 SkTAbs(spotShadowRRect.rect().fTop -
1437 rrect.rect().fTop)),
1438 SkTMax(SkTAbs(spotShadowRRect.rect().fRight -
1439 rrect.rect().fRight),
1440 SkTAbs(spotShadowRRect.rect().fBottom -
1441 rrect.rect().fBottom)));
1442 } else {
Mike Reed242135a2018-02-22 13:41:39 -05001443 SkScalar dr = spotRadius - SkRRectPriv::GetSimpleRadii(rrect).fX;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001444 SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1445 rrect.rect().fLeft + dr,
1446 spotShadowRRect.rect().fTop -
1447 rrect.rect().fTop + dr);
1448 SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1449 rrect.rect().fRight - dr,
1450 spotShadowRRect.rect().fBottom -
1451 rrect.rect().fBottom - dr);
Cary Clarkdf429f32017-11-08 11:44:31 -05001452 maxOffset = SkScalarSqrt(SkTMax(SkPointPriv::LengthSqd(upperLeftOffset),
1453 SkPointPriv::LengthSqd(lowerRightOffset))) + dr;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001454 }
Jim Van Verth4c8c1e82018-04-23 17:14:48 -04001455 insetWidth += SkTMax(blurOutset, maxOffset);
Jim Van Verth3af1af92017-05-18 15:06:54 -04001456 }
1457
1458 // Outset the shadow rrect to the border of the penumbra
1459 SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1460 if (spotShadowRRect.isOval()) {
1461 spotShadowRRect = SkRRect::MakeOval(outsetRect);
1462 } else {
1463 SkScalar outsetRad = spotRadius + blurOutset;
1464 spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1465 }
1466
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001467 GrColor spotColor = SkColorToPremulGrColor(rec.fSpotColor);
Jim Van Verth34d6e4b2017-06-09 11:09:03 -04001468
Robert Phillips7c525e62018-06-12 10:11:12 -04001469 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1470 spotColor,
1471 viewMatrix,
Brian Salomon05969092017-07-13 11:20:51 -04001472 spotShadowRRect,
Jim Van Verth1af03d42017-07-31 09:34:58 -04001473 2.0f * devSpaceSpotBlur,
Brian Salomon05969092017-07-13 11:20:51 -04001474 insetWidth);
Robert Phillipse5763782019-04-17 14:38:24 -04001475 if (op) {
1476 this->addDrawOp(clip, std::move(op));
1477 }
Jim Van Verth3af1af92017-05-18 15:06:54 -04001478 }
1479
1480 return true;
Jim Van Verthc5903412016-11-17 15:27:09 -05001481}
1482
1483///////////////////////////////////////////////////////////////////////////////
1484
Brian Osman11052242016-10-27 14:47:55 -04001485bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001486 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001487 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001488 const SkMatrix& viewMatrix,
1489 const SkRRect& origOuter,
1490 const SkRRect& origInner) {
robertphillips00095892016-02-29 13:50:40 -08001491 SkASSERT(!origInner.isEmpty());
1492 SkASSERT(!origOuter.isEmpty());
1493
Brian Salomon65749212017-12-01 16:01:47 -05001494 SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
1495
Chris Dalton7d6748e2019-03-13 00:34:52 -06001496 GrAAType aaType = this->chooseAAType(aa);
Brian Salomon45839f92017-12-04 09:02:35 -05001497
1498 if (GrAAType::kMSAA == aaType) {
1499 return false;
1500 }
1501
Greg Daniel2655ede2019-04-10 00:49:28 +00001502 if (GrAAType::kCoverage == aaType && SkRRectPriv::IsCircle(*inner)
1503 && SkRRectPriv::IsCircle(*outer)) {
Brian Salomon65749212017-12-01 16:01:47 -05001504 auto outerR = outer->width() / 2.f;
1505 auto innerR = inner->width() / 2.f;
1506 auto cx = outer->getBounds().fLeft + outerR;
1507 auto cy = outer->getBounds().fTop + outerR;
1508 if (SkScalarNearlyEqual(cx, inner->getBounds().fLeft + innerR) &&
1509 SkScalarNearlyEqual(cy, inner->getBounds().fTop + innerR)) {
1510 auto avgR = (innerR + outerR) / 2.f;
1511 auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR);
1512 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
1513 stroke.setStrokeStyle(outerR - innerR);
Greg Daniel2655ede2019-04-10 00:49:28 +00001514 auto op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix,
Robert Phillips7c525e62018-06-12 10:11:12 -04001515 circleBounds, GrStyle(stroke, nullptr),
Brian Salomon62e4f3d2018-04-20 13:54:11 -04001516 this->caps()->shaderCaps());
Brian Salomon65749212017-12-01 16:01:47 -05001517 if (op) {
1518 this->addDrawOp(clip, std::move(op));
1519 return true;
1520 }
Mike Klein16885072018-12-11 09:54:31 -05001521 assert_alive(paint);
Brian Salomon65749212017-12-01 16:01:47 -05001522 }
1523 }
1524
Ethan Nicholas0f3c7322017-11-09 14:51:17 -05001525 GrClipEdgeType innerEdgeType, outerEdgeType;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001526 if (GrAAType::kCoverage == aaType) {
Ethan Nicholas1706f842017-11-10 11:58:19 -05001527 innerEdgeType = GrClipEdgeType::kInverseFillAA;
1528 outerEdgeType = GrClipEdgeType::kFillAA;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001529 } else {
Ethan Nicholas1706f842017-11-10 11:58:19 -05001530 innerEdgeType = GrClipEdgeType::kInverseFillBW;
1531 outerEdgeType = GrClipEdgeType::kFillBW;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001532 }
robertphillips00095892016-02-29 13:50:40 -08001533
robertphillips00095892016-02-29 13:50:40 -08001534 SkMatrix inverseVM;
1535 if (!viewMatrix.isIdentity()) {
1536 if (!origInner.transform(viewMatrix, inner.writable())) {
1537 return false;
1538 }
1539 if (!origOuter.transform(viewMatrix, outer.writable())) {
1540 return false;
1541 }
1542 if (!viewMatrix.invert(&inverseVM)) {
1543 return false;
1544 }
1545 } else {
1546 inverseVM.reset();
halcanary9d524f22016-03-29 09:03:52 -07001547 }
robertphillips00095892016-02-29 13:50:40 -08001548
Ethan Nicholaseace9352018-10-15 20:09:54 +00001549 const auto& caps = *this->caps()->shaderCaps();
robertphillips00095892016-02-29 13:50:40 -08001550 // TODO these need to be a geometry processors
Ethan Nicholaseace9352018-10-15 20:09:54 +00001551 auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps);
robertphillips00095892016-02-29 13:50:40 -08001552 if (!innerEffect) {
1553 return false;
1554 }
1555
Ethan Nicholaseace9352018-10-15 20:09:54 +00001556 auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps);
robertphillips00095892016-02-29 13:50:40 -08001557 if (!outerEffect) {
1558 return false;
1559 }
1560
Brian Salomon82f44312017-01-11 13:42:54 -05001561 paint.addCoverageFragmentProcessor(std::move(innerEffect));
1562 paint.addCoverageFragmentProcessor(std::move(outerEffect));
robertphillips00095892016-02-29 13:50:40 -08001563
1564 SkRect bounds = outer->getBounds();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001565 if (GrAAType::kCoverage == aaType) {
robertphillips00095892016-02-29 13:50:40 -08001566 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1567 }
halcanary9d524f22016-03-29 09:03:52 -07001568
Brian Salomon82f44312017-01-11 13:42:54 -05001569 this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds,
1570 inverseVM);
robertphillips00095892016-02-29 13:50:40 -08001571 return true;
1572}
1573
Brian Osman11052242016-10-27 14:47:55 -04001574void GrRenderTargetContext::drawDRRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001575 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001576 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001577 const SkMatrix& viewMatrix,
1578 const SkRRect& outer,
1579 const SkRRect& inner) {
robertphillips00095892016-02-29 13:50:40 -08001580 ASSERT_SINGLE_OWNER
1581 RETURN_IF_ABANDONED
1582 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001583 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawDRRect", fContext);
robertphillips00095892016-02-29 13:50:40 -08001584
1585 SkASSERT(!outer.isEmpty());
1586 SkASSERT(!inner.isEmpty());
1587
Robert Phillips72152832017-01-25 17:31:35 -05001588 AutoCheckFlush acf(this->drawingManager());
robertphillips00095892016-02-29 13:50:40 -08001589
Brian Salomon82f44312017-01-11 13:42:54 -05001590 if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) {
robertphillips00095892016-02-29 13:50:40 -08001591 return;
1592 }
Mike Klein16885072018-12-11 09:54:31 -05001593 assert_alive(paint);
robertphillips00095892016-02-29 13:50:40 -08001594
1595 SkPath path;
1596 path.setIsVolatile(true);
1597 path.addRRect(inner);
1598 path.addRRect(outer);
1599 path.setFillType(SkPath::kEvenOdd_FillType);
Brian Salomon2fad74a2017-12-20 13:28:55 -05001600 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path));
robertphillips00095892016-02-29 13:50:40 -08001601}
1602
robertphillipsea461502015-05-26 11:38:03 -07001603///////////////////////////////////////////////////////////////////////////////
1604
Brian Osman11052242016-10-27 14:47:55 -04001605void GrRenderTargetContext::drawRegion(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001606 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001607 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001608 const SkMatrix& viewMatrix,
1609 const SkRegion& region,
Stan Iliev73d8fd92017-08-02 15:36:24 -04001610 const GrStyle& style,
1611 const GrUserStencilSettings* ss) {
msarettcc319b92016-08-25 18:07:18 -07001612 ASSERT_SINGLE_OWNER
1613 RETURN_IF_ABANDONED
1614 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001615 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRegion", fContext);
msarettcc319b92016-08-25 18:07:18 -07001616
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001617 if (GrAA::kYes == aa) {
Brian Salomonfc527d22016-12-14 21:07:01 -05001618 // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
Brian Salomonc57c7c92016-12-06 14:47:34 -05001619 // to see whether aa is really required.
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001620 if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
Brian Salomon34169692017-08-28 15:32:01 -04001621 SkScalarIsInt(viewMatrix.getTranslateX()) &&
1622 SkScalarIsInt(viewMatrix.getTranslateY())) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001623 aa = GrAA::kNo;
1624 }
Brian Salomonc57c7c92016-12-06 14:47:34 -05001625 }
msarettcc319b92016-08-25 18:07:18 -07001626 bool complexStyle = !style.isSimpleFill();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001627 if (complexStyle || GrAA::kYes == aa) {
msarettcc319b92016-08-25 18:07:18 -07001628 SkPath path;
1629 region.getBoundaryPath(&path);
Robert Phillips46a13382018-08-23 13:53:01 -04001630 path.setIsVolatile(true);
1631
Brian Salomon82f44312017-01-11 13:42:54 -05001632 return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
msarettcc319b92016-08-25 18:07:18 -07001633 }
1634
Chris Dalton7d6748e2019-03-13 00:34:52 -06001635 GrAAType aaType = this->chooseAAType(GrAA::kNo);
Robert Phillips7c525e62018-06-12 10:11:12 -04001636 std::unique_ptr<GrDrawOp> op = GrRegionOp::Make(fContext, std::move(paint), viewMatrix, region,
1637 aaType, ss);
Brian Salomonf0366322017-07-11 15:53:05 -04001638 this->addDrawOp(clip, std::move(op));
msarettcc319b92016-08-25 18:07:18 -07001639}
1640
Brian Osman11052242016-10-27 14:47:55 -04001641void GrRenderTargetContext::drawOval(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001642 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001643 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001644 const SkMatrix& viewMatrix,
1645 const SkRect& oval,
1646 const GrStyle& style) {
joshualitt1de610a2016-01-06 08:26:09 -08001647 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07001648 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07001649 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001650 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawOval", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -07001651
Robert Phillips7484d202018-07-03 09:09:08 -04001652 const SkStrokeRec& stroke = style.strokeRec();
1653
Brian Salomon62e4f3d2018-04-20 13:54:11 -04001654 if (oval.isEmpty() && !style.pathEffect()) {
Robert Phillips7484d202018-07-03 09:09:08 -04001655 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1656 return;
1657 }
1658
1659 this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
Brian Salomon62e4f3d2018-04-20 13:54:11 -04001660 return;
robertphillipsea461502015-05-26 11:38:03 -07001661 }
1662
Robert Phillips72152832017-01-25 17:31:35 -05001663 AutoCheckFlush acf(this->drawingManager());
csmartdaltona7f29642016-07-07 08:49:11 -07001664
Chris Dalton7d6748e2019-03-13 00:34:52 -06001665 GrAAType aaType = this->chooseAAType(aa);
Chris Dalton0dffbab2019-03-27 13:08:50 -06001666
1667 std::unique_ptr<GrDrawOp> op;
1668 if (style.isSimpleFill()) {
Chris Dalton82eb9e72019-03-21 14:26:39 -06001669 // GrFillRRectOp has special geometry and a fragment-shader branch to conditionally evaluate
1670 // the arc equation. This same special geometry and fragment branch also turn out to be a
1671 // substantial optimization for drawing ovals (namely, by not evaluating the arc equation
1672 // inside the oval's inner diamond). Given these optimizations, it's a clear win to draw
1673 // ovals the exact same way we do round rects.
Chris Daltonebc38c92018-11-28 16:58:09 -07001674 //
Greg Daniel2655ede2019-04-10 00:49:28 +00001675 // However, we still don't draw true circles as round rects in coverage mode, because it can
1676 // cause perf regressions on some platforms as compared to the dedicated circle Op.
1677 if (GrAAType::kCoverage != aaType || oval.height() != oval.width()) {
Chris Daltonbf341ae2019-03-27 00:28:22 +00001678 assert_alive(paint);
Chris Dalton0dffbab2019-03-27 13:08:50 -06001679 op = GrFillRRectOp::Make(fContext, aaType, viewMatrix, SkRRect::MakeOval(oval),
1680 *this->caps(), std::move(paint));
Chris Daltonbf341ae2019-03-27 00:28:22 +00001681 }
Chris Dalton0dffbab2019-03-27 13:08:50 -06001682 }
Greg Daniel2655ede2019-04-10 00:49:28 +00001683 if (!op && GrAAType::kCoverage == aaType) {
Chris Dalton0dffbab2019-03-27 13:08:50 -06001684 assert_alive(paint);
Greg Daniel2655ede2019-04-10 00:49:28 +00001685 op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1686 this->caps()->shaderCaps());
Chris Dalton0dffbab2019-03-27 13:08:50 -06001687 }
1688 if (op) {
1689 this->addDrawOp(clip, std::move(op));
1690 return;
robertphillipsea461502015-05-26 11:38:03 -07001691 }
robertphillipsb56f9272016-02-25 11:03:52 -08001692
Mike Klein16885072018-12-11 09:54:31 -05001693 assert_alive(paint);
Brian Salomon5209d7f2018-04-20 16:52:42 -04001694 this->drawShapeUsingPathRenderer(
1695 clip, std::move(paint), aa, viewMatrix,
1696 GrShape(SkRRect::MakeOval(oval), SkPath::kCW_Direction, 2, false, style));
robertphillipsea461502015-05-26 11:38:03 -07001697}
1698
Brian Osman11052242016-10-27 14:47:55 -04001699void GrRenderTargetContext::drawArc(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001700 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001701 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001702 const SkMatrix& viewMatrix,
1703 const SkRect& oval,
1704 SkScalar startAngle,
1705 SkScalar sweepAngle,
1706 bool useCenter,
1707 const GrStyle& style) {
Robert Phillipsf1d0ced2017-02-10 09:31:01 -05001708 ASSERT_SINGLE_OWNER
1709 RETURN_IF_ABANDONED
1710 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001711 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawArc", fContext);
Robert Phillipsf1d0ced2017-02-10 09:31:01 -05001712
1713 AutoCheckFlush acf(this->drawingManager());
1714
Chris Dalton7d6748e2019-03-13 00:34:52 -06001715 GrAAType aaType = this->chooseAAType(aa);
Greg Daniel2655ede2019-04-10 00:49:28 +00001716 if (GrAAType::kCoverage == aaType) {
1717 const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
1718 std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(fContext,
1719 std::move(paint),
1720 viewMatrix,
1721 oval,
1722 startAngle,
1723 sweepAngle,
1724 useCenter,
1725 style,
1726 shaderCaps);
1727 if (op) {
1728 this->addDrawOp(clip, std::move(op));
1729 return;
1730 }
1731 assert_alive(paint);
bsalomon4f3a0ca2016-08-22 13:14:26 -07001732 }
Brian Salomone4949402018-04-26 15:22:04 -04001733 this->drawShapeUsingPathRenderer(
1734 clip, std::move(paint), aa, viewMatrix,
1735 GrShape::MakeArc(oval, startAngle, sweepAngle, useCenter, style));
bsalomon4f3a0ca2016-08-22 13:14:26 -07001736}
1737
Brian Osman11052242016-10-27 14:47:55 -04001738void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001739 GrPaint&& paint,
Brian Osman11052242016-10-27 14:47:55 -04001740 const SkMatrix& viewMatrix,
Brian Salomon2a943df2018-05-04 13:43:19 -04001741 sk_sp<GrTextureProxy> image,
1742 sk_sp<GrColorSpaceXform> csxf,
1743 GrSamplerState::Filter filter,
Brian Osman11052242016-10-27 14:47:55 -04001744 std::unique_ptr<SkLatticeIter> iter,
1745 const SkRect& dst) {
joshualitt1de610a2016-01-06 08:26:09 -08001746 ASSERT_SINGLE_OWNER
joshualitt33a5fce2015-11-18 13:28:51 -08001747 RETURN_IF_ABANDONED
1748 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001749 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawImageLattice", fContext);
joshualitt33a5fce2015-11-18 13:28:51 -08001750
Robert Phillips72152832017-01-25 17:31:35 -05001751 AutoCheckFlush acf(this->drawingManager());
joshualitt33a5fce2015-11-18 13:28:51 -08001752
Brian Salomon2a943df2018-05-04 13:43:19 -04001753 std::unique_ptr<GrDrawOp> op =
Robert Phillips7c525e62018-06-12 10:11:12 -04001754 GrLatticeOp::MakeNonAA(fContext, std::move(paint), viewMatrix, std::move(image),
1755 std::move(csxf), filter, std::move(iter), dst);
Brian Salomon815486c2017-07-11 08:52:13 -04001756 this->addDrawOp(clip, std::move(op));
joshualitt33a5fce2015-11-18 13:28:51 -08001757}
1758
Greg Daniel64cc9aa2018-10-19 13:54:56 -04001759void GrRenderTargetContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
1760 const SkRect& bounds) {
1761 std::unique_ptr<GrOp> op(GrDrawableOp::Make(fContext, std::move(drawable), bounds));
1762 SkASSERT(op);
1763 this->getRTOpList()->addOp(std::move(op), *this->caps());
1764}
1765
Brian Salomon031b0ba2019-05-23 11:05:26 -04001766sk_sp<GrRenderTargetContext> GrRenderTargetContext::rescale(const SkImageInfo& info,
1767 const SkIRect& srcRect,
1768 SkSurface::RescaleGamma rescaleGamma,
1769 SkFilterQuality rescaleQuality) {
Brian Salomonab32f652019-05-10 14:24:50 -04001770 auto direct = fContext->priv().asDirectContext();
1771 if (!direct) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001772 return nullptr;
Brian Salomonab32f652019-05-10 14:24:50 -04001773 }
1774 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001775 return nullptr;
1776 }
1777
1778 // We currently don't know our own alpha type, we assume it's premul if we have an alpha channel
1779 // and opaque otherwise.
1780 if (!GrPixelConfigIsAlphaOnly(fRenderTargetProxy->config()) &&
1781 info.alphaType() != kPremul_SkAlphaType) {
1782 return nullptr;
1783 }
1784
1785 int srcW = srcRect.width();
1786 int srcH = srcRect.height();
1787 int srcX = srcRect.fLeft;
1788 int srcY = srcRect.fTop;
Greg Daniel46cfbc62019-06-07 11:43:30 -04001789 sk_sp<GrTextureProxy> texProxy = sk_ref_sp(fRenderTargetProxy->asTextureProxy());
Brian Salomon031b0ba2019-05-23 11:05:26 -04001790 SkCanvas::SrcRectConstraint constraint = SkCanvas::kStrict_SrcRectConstraint;
Greg Daniel46cfbc62019-06-07 11:43:30 -04001791 if (!texProxy) {
1792 texProxy = GrSurfaceProxy::Copy(fContext, fRenderTargetProxy.get(), GrMipMapped::kNo,
1793 srcRect, SkBackingFit::kApprox, SkBudgeted::kNo);
1794 if (!texProxy) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001795 return nullptr;
1796 }
1797 srcX = 0;
1798 srcY = 0;
1799 constraint = SkCanvas::kFast_SrcRectConstraint;
Brian Salomon031b0ba2019-05-23 11:05:26 -04001800 }
1801
1802 float sx = (float)info.width() / srcW;
1803 float sy = (float)info.height() / srcH;
1804
1805 // How many bilerp/bicubic steps to do in X and Y. + means upscaling, - means downscaling.
1806 int stepsX;
1807 int stepsY;
1808 if (rescaleQuality > kNone_SkFilterQuality) {
1809 stepsX = static_cast<int>((sx > 1.f) ? std::ceil(std::log2f(sx))
1810 : std::floor(std::log2f(sx)));
1811 stepsY = static_cast<int>((sy > 1.f) ? std::ceil(std::log2f(sy))
1812 : std::floor(std::log2f(sy)));
1813 } else {
1814 stepsX = sx != 1.f;
1815 stepsY = sy != 1.f;
1816 }
1817 SkASSERT(stepsX || stepsY);
Brian Salomon024bd002019-06-11 11:38:16 -04001818 auto rescaleColorSapce = this->colorSpaceInfo().refColorSpace();
Brian Salomon031b0ba2019-05-23 11:05:26 -04001819 // Assume we should ignore the rescale linear request if the surface has no color space since
1820 // it's unclear how we'd linearize from an unknown color space.
1821 if (rescaleGamma == SkSurface::RescaleGamma::kLinear &&
Brian Salomon024bd002019-06-11 11:38:16 -04001822 rescaleColorSapce.get() && !rescaleColorSapce->gammaIsLinear()) {
1823 auto cs = rescaleColorSapce->makeLinearGamma();
Brian Salomon031b0ba2019-05-23 11:05:26 -04001824 auto backendFormat = this->caps()->getBackendFormatFromGrColorType(GrColorType::kRGBA_F16,
1825 GrSRGBEncoded::kNo);
Brian Salomon024bd002019-06-11 11:38:16 -04001826 auto xform = GrColorSpaceXform::Make(rescaleColorSapce.get(), kPremul_SkAlphaType, cs.get(),
Greg Daniel46cfbc62019-06-07 11:43:30 -04001827 kPremul_SkAlphaType);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001828 // We'll fall back to kRGBA_8888 if half float not supported.
1829 auto linearRTC = fContext->priv().makeDeferredRenderTargetContextWithFallback(
Greg Daniel46cfbc62019-06-07 11:43:30 -04001830 backendFormat, SkBackingFit::kExact, srcW, srcH, kRGBA_half_GrPixelConfig, cs, 1,
1831 GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001832 if (!linearRTC) {
1833 return nullptr;
1834 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001835 linearRTC->drawTexture(GrNoClip(), texProxy,
Brian Salomon031b0ba2019-05-23 11:05:26 -04001836 GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
1837 SK_PMColor4fWHITE, SkRect::Make(srcRect), SkRect::MakeWH(srcW, srcH),
1838 GrAA::kNo, GrQuadAAFlags::kNone, constraint, SkMatrix::I(),
1839 std::move(xform));
Greg Daniel46cfbc62019-06-07 11:43:30 -04001840 texProxy = linearRTC->asTextureProxyRef();
Brian Salomon024bd002019-06-11 11:38:16 -04001841 rescaleColorSapce = std::move(cs);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001842 srcX = 0;
1843 srcY = 0;
1844 constraint = SkCanvas::kFast_SrcRectConstraint;
1845 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001846 sk_sp<GrRenderTargetContext> currRTC;
Brian Salomon031b0ba2019-05-23 11:05:26 -04001847 while (stepsX || stepsY) {
1848 int nextW = info.width();
1849 int nextH = info.height();
1850 if (stepsX < 0) {
1851 nextW = info.width() << (-stepsX - 1);
1852 stepsX++;
1853 } else if (stepsX != 0) {
1854 if (stepsX > 1) {
1855 nextW = srcW * 2;
1856 }
1857 --stepsX;
1858 }
1859 if (stepsY < 0) {
1860 nextH = info.height() << (-stepsY - 1);
1861 stepsY++;
1862 } else if (stepsY != 0) {
1863 if (stepsY > 1) {
1864 nextH = srcH * 2;
1865 }
1866 --stepsY;
1867 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001868 GrBackendFormat backendFormat = texProxy->backendFormat().makeTexture2D();
1869 GrPixelConfig config = texProxy->config();
Brian Salomon024bd002019-06-11 11:38:16 -04001870 auto cs = rescaleColorSapce;
Brian Salomon900dda82019-06-03 13:12:55 -04001871 sk_sp<GrColorSpaceXform> xform;
Brian Salomon031b0ba2019-05-23 11:05:26 -04001872 if (!stepsX && !stepsY) {
1873 // Might as well fold conversion to final info in the last step.
1874 backendFormat = this->caps()->getBackendFormatFromColorType(info.colorType());
1875 config = this->caps()->getConfigFromBackendFormat(backendFormat, info.colorType());
1876 cs = info.refColorSpace();
Brian Salomon024bd002019-06-11 11:38:16 -04001877 xform = GrColorSpaceXform::Make(rescaleColorSapce.get(),
Brian Salomon900dda82019-06-03 13:12:55 -04001878 kPremul_SkAlphaType, cs.get(), info.alphaType());
Brian Salomon031b0ba2019-05-23 11:05:26 -04001879 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001880 currRTC = fContext->priv().makeDeferredRenderTargetContextWithFallback(
Brian Salomon031b0ba2019-05-23 11:05:26 -04001881 backendFormat, SkBackingFit::kExact, nextW, nextH, config, std::move(cs), 1,
1882 GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
Greg Daniel46cfbc62019-06-07 11:43:30 -04001883 if (!currRTC) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001884 return nullptr;
1885 }
1886 auto dstRect = SkRect::MakeWH(nextW, nextH);
1887 if (rescaleQuality == kHigh_SkFilterQuality) {
1888 SkMatrix matrix;
1889 matrix.setScaleTranslate((float)srcW / nextW, (float)srcH / nextH, srcX, srcY);
1890 std::unique_ptr<GrFragmentProcessor> fp;
Brian Salomona86fc7a2019-05-28 20:42:58 -04001891 auto dir = GrBicubicEffect::Direction::kXY;
1892 if (nextW == srcW) {
1893 dir = GrBicubicEffect::Direction::kY;
1894 } else if (nextH == srcH) {
1895 dir = GrBicubicEffect::Direction::kX;
1896 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001897 if (srcW != texProxy->width() || srcH != texProxy->height()) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001898 auto domain = GrTextureDomain::MakeTexelDomain(
1899 SkIRect::MakeXYWH(srcX, srcY, srcW, srcH), GrTextureDomain::kClamp_Mode);
Brian Salomon1127c0b2019-06-13 20:22:10 +00001900 fp = GrBicubicEffect::Make(texProxy, matrix, domain, dir, kPremul_SkAlphaType);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001901 } else {
Brian Salomon1127c0b2019-06-13 20:22:10 +00001902 fp = GrBicubicEffect::Make(texProxy, matrix, dir, kPremul_SkAlphaType);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001903 }
Brian Salomon900dda82019-06-03 13:12:55 -04001904 if (xform) {
1905 fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(xform));
1906 }
Brian Salomon031b0ba2019-05-23 11:05:26 -04001907 GrPaint paint;
1908 paint.addColorFragmentProcessor(std::move(fp));
1909 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Greg Daniel46cfbc62019-06-07 11:43:30 -04001910 currRTC->drawFilledRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
Brian Salomon031b0ba2019-05-23 11:05:26 -04001911 dstRect);
1912 } else {
1913 auto filter = rescaleQuality == kNone_SkFilterQuality ? GrSamplerState::Filter::kNearest
1914 : GrSamplerState::Filter::kBilerp;
1915 auto srcSubset = SkRect::MakeXYWH(srcX, srcY, srcW, srcH);
Greg Daniel46cfbc62019-06-07 11:43:30 -04001916 currRTC->drawTexture(GrNoClip(), texProxy, filter, SkBlendMode::kSrc, SK_PMColor4fWHITE,
1917 srcSubset, dstRect, GrAA::kNo, GrQuadAAFlags::kNone, constraint,
1918 SkMatrix::I(), std::move(xform));
Brian Salomon031b0ba2019-05-23 11:05:26 -04001919 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001920 texProxy = currRTC->asTextureProxyRef();
Brian Salomon031b0ba2019-05-23 11:05:26 -04001921 srcX = srcY = 0;
1922 srcW = nextW;
1923 srcH = nextH;
1924 constraint = SkCanvas::kFast_SrcRectConstraint;
1925 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001926 SkASSERT(currRTC);
1927 return currRTC;
Brian Salomon031b0ba2019-05-23 11:05:26 -04001928}
1929
1930void GrRenderTargetContext::asyncRescaleAndReadPixels(
1931 const SkImageInfo& info, const SkIRect& srcRect, SkSurface::RescaleGamma rescaleGamma,
1932 SkFilterQuality rescaleQuality, ReadPixelsCallback callback, ReadPixelsContext context) {
1933 auto direct = fContext->priv().asDirectContext();
1934 if (!direct) {
1935 callback(context, nullptr, 0);
1936 return;
1937 }
1938 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
1939 callback(context, nullptr, 0);
1940 return;
Brian Salomonab32f652019-05-10 14:24:50 -04001941 }
1942 // We currently don't know our own alpha type, we assume it's premul if we have an alpha channel
1943 // and opaque otherwise.
Brian Salomon201700f2019-05-17 12:05:44 -04001944 if (!GrPixelConfigIsAlphaOnly(fRenderTargetProxy->config()) &&
1945 info.alphaType() != kPremul_SkAlphaType) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001946 callback(context, nullptr, 0);
1947 return;
1948 }
1949 auto dstCT = SkColorTypeToGrColorType(info.colorType());
1950 bool needsRescale = srcRect.width() != info.width() || srcRect.height() != info.height();
1951 GrPixelConfig configOfFinalContext = fRenderTargetProxy->config();
1952 if (needsRescale) {
1953 auto backendFormat = this->caps()->getBackendFormatFromColorType(info.colorType());
1954 configOfFinalContext =
1955 this->caps()->getConfigFromBackendFormat(backendFormat, info.colorType());
1956 }
1957 auto readCT = this->caps()->supportedReadPixelsColorType(configOfFinalContext, dstCT);
1958 // Fail if we can't do a CPU conversion from readCT to dstCT.
1959 if (GrColorTypeToSkColorType(readCT) == kUnknown_SkColorType) {
1960 callback(context, nullptr, 0);
1961 return;
1962 }
1963 // Fail if readCT does not have all of readCT's color channels.
1964 if (GrColorTypeComponentFlags(dstCT) & ~GrColorTypeComponentFlags(readCT)) {
1965 callback(context, nullptr, 0);
1966 return;
1967 }
1968
1969 sk_sp<GrRenderTargetContext> rtc;
1970 int x = srcRect.fLeft;
1971 int y = srcRect.fTop;
1972 if (needsRescale) {
1973 rtc = this->rescale(info, srcRect, rescaleGamma, rescaleQuality);
1974 if (!rtc) {
1975 callback(context, nullptr, 0);
1976 return;
1977 }
1978 SkASSERT(SkColorSpace::Equals(rtc->colorSpaceInfo().colorSpace(), info.colorSpace()));
1979 SkASSERT(rtc->origin() == kTopLeft_GrSurfaceOrigin);
1980 x = y = 0;
1981 } else {
1982 sk_sp<GrColorSpaceXform> xform =
1983 GrColorSpaceXform::Make(this->colorSpaceInfo().colorSpace(), kPremul_SkAlphaType,
1984 info.colorSpace(), info.alphaType());
1985 // Insert a draw to a temporary surface if we need to do a y-flip or color space conversion.
1986 if (this->origin() == kBottomLeft_GrSurfaceOrigin || xform) {
1987 sk_sp<GrTextureProxy> texProxy = sk_ref_sp(fRenderTargetProxy->asTextureProxy());
1988 const auto backendFormat = fRenderTargetProxy->backendFormat().makeTexture2D();
1989 SkRect srcRectToDraw = SkRect::Make(srcRect);
1990 // If the src is not texturable first try to make a copy to a texture.
1991 if (!texProxy) {
Greg Daniel46cfbc62019-06-07 11:43:30 -04001992 texProxy = GrSurfaceProxy::Copy(fContext, fRenderTargetProxy.get(),
1993 GrMipMapped::kNo, srcRect, SkBackingFit::kApprox,
1994 SkBudgeted::kNo);
1995 if (!texProxy) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001996 callback(context, nullptr, 0);
1997 return;
1998 }
Brian Salomon031b0ba2019-05-23 11:05:26 -04001999 srcRectToDraw = SkRect::MakeWH(srcRect.width(), srcRect.height());
2000 }
2001 rtc = direct->priv().makeDeferredRenderTargetContext(
2002 backendFormat, SkBackingFit::kApprox, srcRect.width(), srcRect.height(),
2003 fRenderTargetProxy->config(), info.refColorSpace(), 1, GrMipMapped::kNo,
2004 kTopLeft_GrSurfaceOrigin);
2005 if (!rtc) {
2006 callback(context, nullptr, 0);
2007 return;
2008 }
2009 rtc->drawTexture(GrNoClip(), std::move(texProxy), GrSamplerState::Filter::kNearest,
2010 SkBlendMode::kSrc, SK_PMColor4fWHITE, srcRectToDraw,
2011 SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo,
2012 GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
2013 std::move(xform));
2014 x = y = 0;
2015 } else {
2016 rtc = sk_ref_sp(this);
2017 }
2018 }
Brian Salomon024bd002019-06-11 11:38:16 -04002019 return rtc->asyncReadPixels(SkIRect::MakeXYWH(x, y, info.width(), info.height()),
2020 info.colorType(), callback, context);
Brian Salomon031b0ba2019-05-23 11:05:26 -04002021}
2022
Brian Salomon024bd002019-06-11 11:38:16 -04002023GrRenderTargetContext::PixelTransferResult GrRenderTargetContext::transferPixels(
2024 GrColorType dstCT, const SkIRect& rect) {
2025 SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
2026 SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
Brian Salomon031b0ba2019-05-23 11:05:26 -04002027 auto direct = fContext->priv().asDirectContext();
2028 if (!direct) {
Brian Salomon024bd002019-06-11 11:38:16 -04002029 return {};
Brian Salomon031b0ba2019-05-23 11:05:26 -04002030 }
2031 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
Brian Salomon024bd002019-06-11 11:38:16 -04002032 return {};
Brian Salomon031b0ba2019-05-23 11:05:26 -04002033 }
Brian Salomonab32f652019-05-10 14:24:50 -04002034 auto readCT = this->caps()->supportedReadPixelsColorType(fRenderTargetProxy->config(), dstCT);
Brian Salomoncd734f62019-05-10 16:32:54 -04002035 // Fail if we can't do a CPU conversion from readCT to dstCT.
Brian Salomon024bd002019-06-11 11:38:16 -04002036 if (readCT != dstCT && (GrColorTypeToSkColorType(readCT) == kUnknown_SkColorType ||
2037 GrColorTypeToSkColorType(dstCT) == kUnknown_SkColorType)) {
2038 return {};
Brian Salomonab32f652019-05-10 14:24:50 -04002039 }
Brian Salomoncd734f62019-05-10 16:32:54 -04002040 // Fail if readCT does not have all of readCT's color channels.
2041 if (GrColorTypeComponentFlags(dstCT) & ~GrColorTypeComponentFlags(readCT)) {
Brian Salomon024bd002019-06-11 11:38:16 -04002042 return {};
Brian Salomonab32f652019-05-10 14:24:50 -04002043 }
2044
Brian Salomon031b0ba2019-05-23 11:05:26 -04002045 if (!this->caps()->transferBufferSupport() ||
2046 !this->caps()->transferFromOffsetAlignment(readCT)) {
Brian Salomon024bd002019-06-11 11:38:16 -04002047 return {};
2048 }
2049
2050 size_t rowBytes = GrColorTypeBytesPerPixel(readCT) * rect.width();
2051 size_t size = rowBytes * rect.height();
2052 auto buffer = direct->priv().resourceProvider()->createBuffer(
2053 size, GrGpuBufferType::kXferGpuToCpu, GrAccessPattern::kStream_GrAccessPattern);
2054 if (!buffer) {
2055 return {};
2056 }
2057 this->getRTOpList()->addOp(GrTransferFromOp::Make(fContext, rect, readCT, buffer, 0),
2058 *this->caps());
2059 PixelTransferResult result;
2060 result.fTransferBuffer = std::move(buffer);
2061 if (readCT != dstCT) {
2062 result.fPixelConverter =
2063 [w = rect.width(), h = rect.height(), dstCT = GrColorTypeToSkColorType(dstCT),
2064 srcCT = GrColorTypeToSkColorType(readCT)](void* dst, const void* src) {
2065 auto dstII = SkImageInfo::Make(w, h, dstCT, kPremul_SkAlphaType, nullptr);
2066 auto srcII = SkImageInfo::Make(w, h, srcCT, kPremul_SkAlphaType, nullptr);
2067 SkConvertPixels(dstII, dst, w * SkColorTypeBytesPerPixel(dstCT), srcII, src,
2068 w * SkColorTypeBytesPerPixel(srcCT));
2069 };
2070 }
2071 return result;
2072}
2073
2074void GrRenderTargetContext::asyncReadPixels(const SkIRect& rect, SkColorType colorType,
2075 ReadPixelsCallback callback,
2076 ReadPixelsContext context) {
2077 SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
2078 SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
2079
2080 auto transferResult = this->transferPixels(SkColorTypeToGrColorType(colorType), rect);
2081
2082 if (!transferResult.fTransferBuffer) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04002083 SkAutoPixmapStorage pm;
Brian Salomon024bd002019-06-11 11:38:16 -04002084 auto ii = SkImageInfo::Make(rect.width(), rect.height(), colorType, kPremul_SkAlphaType,
2085 this->colorSpaceInfo().refColorSpace());
2086 pm.alloc(ii);
2087 if (!this->readPixels(ii, pm.writable_addr(), pm.rowBytes(), rect.fLeft, rect.fTop)) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04002088 callback(context, nullptr, 0);
Brian Salomonab32f652019-05-10 14:24:50 -04002089 }
Brian Salomon031b0ba2019-05-23 11:05:26 -04002090 callback(context, pm.addr(), pm.rowBytes());
2091 return;
Brian Salomonab32f652019-05-10 14:24:50 -04002092 }
Brian Salomoncd734f62019-05-10 16:32:54 -04002093
Brian Salomonab32f652019-05-10 14:24:50 -04002094 struct FinishContext {
2095 ReadPixelsCallback* fClientCallback;
2096 ReadPixelsContext fClientContext;
Brian Salomon024bd002019-06-11 11:38:16 -04002097 int fW, fH;
2098 SkColorType fColorType;
2099 PixelTransferResult fTransferResult;
Brian Salomonab32f652019-05-10 14:24:50 -04002100 };
2101 // Assumption is that the caller would like to flush. We could take a parameter or require an
2102 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
2103 // callback to GrGpu until after the next flush that flushes our op list, though.
Brian Salomon024bd002019-06-11 11:38:16 -04002104 auto* finishContext = new FinishContext{callback, context, rect.width(),
2105 rect.height(), colorType, std::move(transferResult)};
Brian Salomonab32f652019-05-10 14:24:50 -04002106 auto finishCallback = [](GrGpuFinishedContext c) {
Brian Salomon024bd002019-06-11 11:38:16 -04002107 const auto* context = reinterpret_cast<const FinishContext*>(c);
2108 const void* data = context->fTransferResult.fTransferBuffer->map();
Brian Salomoncd734f62019-05-10 16:32:54 -04002109 if (!data) {
2110 (*context->fClientCallback)(context->fClientContext, nullptr, 0);
2111 delete context;
2112 return;
2113 }
2114 SkAutoPixmapStorage pm;
Brian Salomon024bd002019-06-11 11:38:16 -04002115 if (context->fTransferResult.fPixelConverter) {
2116 pm.alloc(SkImageInfo::Make(context->fW, context->fH, context->fColorType,
2117 kPremul_SkAlphaType, nullptr));
2118 context->fTransferResult.fPixelConverter(pm.writable_addr(), data);
2119 data = pm.addr();
Brian Salomoncd734f62019-05-10 16:32:54 -04002120 }
Brian Salomon024bd002019-06-11 11:38:16 -04002121 (*context->fClientCallback)(context->fClientContext, data,
2122 context->fW * SkColorTypeBytesPerPixel(context->fColorType));
2123 delete context;
2124 };
2125 GrFlushInfo flushInfo;
2126 flushInfo.fFinishedContext = finishContext;
2127 flushInfo.fFinishedProc = finishCallback;
2128 this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
2129}
2130
2131void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(
2132 SkYUVColorSpace yuvColorSpace, sk_sp<SkColorSpace> dstColorSpace, const SkIRect& srcRect,
2133 int dstW, int dstH, RescaleGamma rescaleGamma, SkFilterQuality rescaleQuality,
2134 ReadPixelsCallbackYUV420 callback, ReadPixelsContext context) {
2135 SkASSERT(srcRect.fLeft >= 0 && srcRect.fRight <= this->width());
2136 SkASSERT(srcRect.fTop >= 0 && srcRect.fBottom <= this->height());
2137 SkASSERT((dstW % 2 == 0) && (dstH % 2 == 0));
2138 auto direct = fContext->priv().asDirectContext();
2139 if (!direct) {
2140 callback(context, nullptr, nullptr);
2141 return;
2142 }
2143 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
2144 callback(context, nullptr, nullptr);
2145 return;
2146 }
2147 if (dstW & 0x1) {
2148 return;
2149 }
2150 int x = srcRect.fLeft;
2151 int y = srcRect.fTop;
2152 auto rtc = sk_ref_sp(this);
2153 bool needsRescale = srcRect.width() != dstW || srcRect.height() != dstH;
2154 if (needsRescale) {
2155 auto info = SkImageInfo::Make(dstW, dstH, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
2156 dstColorSpace);
2157 // TODO: Incorporate the YUV conversion into last pass of rescaling.
2158 rtc = this->rescale(info, srcRect, rescaleGamma, rescaleQuality);
2159 if (!rtc) {
2160 callback(context, nullptr, nullptr);
2161 return;
Brian Salomonab32f652019-05-10 14:24:50 -04002162 }
Brian Salomon024bd002019-06-11 11:38:16 -04002163 SkASSERT(SkColorSpace::Equals(rtc->colorSpaceInfo().colorSpace(), info.colorSpace()));
2164 SkASSERT(rtc->origin() == kTopLeft_GrSurfaceOrigin);
2165 x = y = 0;
2166 } else {
2167 sk_sp<GrColorSpaceXform> xform =
2168 GrColorSpaceXform::Make(this->colorSpaceInfo().colorSpace(), kPremul_SkAlphaType,
2169 dstColorSpace.get(), kPremul_SkAlphaType);
2170 if (xform) {
2171 sk_sp<GrTextureProxy> texProxy = this->asTextureProxyRef();
2172 // TODO: Do something if the input is not a texture already.
2173 if (!texProxy) {
2174 callback(context, nullptr, nullptr);
2175 return;
2176 }
2177 const auto backendFormat =
2178 this->caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
2179 SkRect srcRectToDraw = SkRect::Make(srcRect);
2180 rtc = direct->priv().makeDeferredRenderTargetContext(
2181 backendFormat, SkBackingFit::kApprox, dstW, dstH, fRenderTargetProxy->config(),
2182 dstColorSpace, 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
2183 if (!rtc) {
2184 callback(context, nullptr, nullptr);
2185 return;
2186 }
2187 rtc->drawTexture(GrNoClip(), std::move(texProxy), GrSamplerState::Filter::kNearest,
2188 SkBlendMode::kSrc, SK_PMColor4fWHITE, srcRectToDraw,
2189 SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo,
2190 GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
2191 std::move(xform));
2192 x = y = 0;
2193 }
2194 }
2195 auto srcProxy = rtc->asTextureProxyRef();
2196 // TODO: Do something if the input is not a texture already.
2197 if (!srcProxy) {
2198 callback(context, nullptr, nullptr);
2199 return;
2200 }
2201 GrPixelConfig planeConfig = kAlpha_8_GrPixelConfig;
2202 GrColorType planeColorType = GrColorType::kAlpha_8;
2203 if (this->caps()->supportedReadPixelsColorType(planeConfig, planeColorType) !=
2204 GrColorType::kAlpha_8) {
2205 // TODO: Because there are issues with reading back/transferring A8 textures on GL, we are
2206 // currently using RGBA textures for the planes. Fix this once the A8 read back/transfer
2207 // issues are addressed.
2208 planeConfig = kRGBA_8888_GrPixelConfig;
2209 planeColorType = GrColorType::kRGBA_8888;
2210 }
2211 const auto backendFormat = this->caps()->getBackendFormatFromGrColorType(
2212 planeColorType, GrSRGBEncoded::kNo);
2213 auto yRTC = direct->priv().makeDeferredRenderTargetContext(
2214 backendFormat, SkBackingFit::kApprox, dstW, dstH, planeConfig, dstColorSpace,
2215 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
2216 auto uRTC = direct->priv().makeDeferredRenderTargetContext(
2217 backendFormat, SkBackingFit::kApprox, dstW / 2, dstH / 2, planeConfig,
2218 dstColorSpace, 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
2219 auto vRTC = direct->priv().makeDeferredRenderTargetContext(
2220 backendFormat, SkBackingFit::kApprox, dstW / 2, dstH / 2, planeConfig,
2221 dstColorSpace, 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
2222 if (!yRTC || !uRTC || !vRTC) {
2223 callback(context, nullptr, nullptr);
2224 return;
2225 }
2226
2227 static constexpr float kRec601M[] {
2228 65.481f / 255, 128.553f / 255, 24.966f / 255, 16.f / 255, // y
2229 -37.797f / 255, -74.203f / 255, 112.0f / 255, 128.f / 255, // u
2230 112.f / 255, -93.786f / 255, -18.214f / 255, 128.f / 255, // v
2231 };
2232 static constexpr float kRec709M[] {
2233 45.5594f / 255, 156.6288f / 255, 15.8118f / 255, 16.f / 255, // y
2234 -25.6642f / 255, -86.3358f / 255, 112.f / 255, 128.f / 255, // u
2235 112.f / 255, -101.7303f / 255, -10.2697f / 255, 128.f / 255, // v
2236 };
2237 static constexpr float kJpegM[] {
2238 0.299f , 0.587f , 0.114f , 0.f / 255, // y
2239 -0.168736f, -0.331264f, 0.5f , 128.f / 255, // u
2240 0.5f , -0.418688f, -0.081312f, 128.f / 255, // v
2241 };
2242 static constexpr float kIM[] {
2243 1.f, 0.f, 0.f, 0.f,
2244 0.f, 1.f, 0.f, 0.f,
2245 0.f, 0.f, 1.f, 0.f,
2246 };
2247 const float* baseM = kIM;
2248 switch (yuvColorSpace) {
2249 case kRec601_SkYUVColorSpace:
2250 baseM = kRec601M;
2251 break;
2252 case kRec709_SkYUVColorSpace:
2253 baseM = kRec709M;
2254 break;
2255 case kJPEG_SkYUVColorSpace:
2256 baseM = kJpegM;
2257 break;
2258 case kIdentity_SkYUVColorSpace:
2259 baseM = kIM;
2260 break;
2261 }
2262 // TODO: Use one transfer buffer for all three planes to reduce map/unmap cost?
2263
2264 auto texMatrix = SkMatrix::MakeTrans(x, y);
2265
2266 // This matrix generates (r,g,b,a) = (0, 0, 0, y)
2267 float yM[20];
Brian Salomondf586b72019-06-11 13:26:37 -04002268 std::fill_n(yM, 15, 0.f);
Brian Salomon024bd002019-06-11 11:38:16 -04002269 yM[15] = baseM[0]; yM[16] = baseM[1]; yM[17] = baseM[2]; yM[18] = 0; yM[19] = baseM[3];
2270 GrPaint yPaint;
2271 yPaint.addColorTextureProcessor(srcProxy, texMatrix);
2272 auto yFP = GrColorMatrixFragmentProcessor::Make(yM, false, true, false);
2273 yPaint.addColorFragmentProcessor(std::move(yFP));
2274 yPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
2275 yRTC->drawFilledRect(GrNoClip(), std::move(yPaint), GrAA::kNo, SkMatrix::I(),
2276 SkRect::MakeWH(dstW, dstH));
2277 auto yTransfer = yRTC->transferPixels(GrColorType::kAlpha_8,
2278 SkIRect::MakeWH(yRTC->width(), yRTC->height()));
2279 if (!yTransfer.fTransferBuffer) {
2280 callback(context, nullptr, nullptr);
2281 return;
2282 }
2283
2284 texMatrix.preScale(2.f, 2.f);
2285 // This matrix generates (r,g,b,a) = (0, 0, 0, u)
2286 float uM[20];
Brian Salomondf586b72019-06-11 13:26:37 -04002287 std::fill_n(uM, 15, 0.f);
Brian Salomon024bd002019-06-11 11:38:16 -04002288 uM[15] = baseM[4]; uM[16] = baseM[5]; uM[17] = baseM[6]; uM[18] = 0; uM[19] = baseM[7];
2289 GrPaint uPaint;
2290 uPaint.addColorTextureProcessor(srcProxy, texMatrix, GrSamplerState::ClampBilerp());
2291 auto uFP = GrColorMatrixFragmentProcessor::Make(uM, false, true, false);
2292 uPaint.addColorFragmentProcessor(std::move(uFP));
2293 uPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
2294 uRTC->drawFilledRect(GrNoClip(), std::move(uPaint), GrAA::kNo, SkMatrix::I(),
2295 SkRect::MakeWH(dstW / 2, dstH / 2));
2296 auto uTransfer = uRTC->transferPixels(GrColorType::kAlpha_8,
2297 SkIRect::MakeWH(uRTC->width(), uRTC->height()));
2298 if (!uTransfer.fTransferBuffer) {
2299 callback(context, nullptr, nullptr);
2300 return;
2301 }
2302
2303 // This matrix generates (r,g,b,a) = (0, 0, 0, v)
2304 float vM[20];
Brian Salomondf586b72019-06-11 13:26:37 -04002305 std::fill_n(vM, 15, 0.f);
Brian Salomon024bd002019-06-11 11:38:16 -04002306 vM[15] = baseM[8]; vM[16] = baseM[9]; vM[17] = baseM[10]; vM[18] = 0; vM[19] = baseM[11];
2307 GrPaint vPaint;
2308 vPaint.addColorTextureProcessor(srcProxy, texMatrix, GrSamplerState::ClampBilerp());
2309 auto vFP = GrColorMatrixFragmentProcessor::Make(vM, false, true, false);
2310 vPaint.addColorFragmentProcessor(std::move(vFP));
2311 vPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
2312 vRTC->drawFilledRect(GrNoClip(), std::move(vPaint), GrAA::kNo, SkMatrix::I(),
2313 SkRect::MakeWH(dstW / 2, dstH / 2));
2314 auto vTransfer = vRTC->transferPixels(GrColorType::kAlpha_8,
2315 SkIRect::MakeWH(vRTC->width(), vRTC->height()));
2316 if (!vTransfer.fTransferBuffer) {
2317 callback(context, nullptr, nullptr);
2318 return;
2319 }
2320
2321 struct FinishContext {
2322 ReadPixelsCallbackYUV420* fClientCallback;
2323 ReadPixelsContext fClientContext;
2324 int fW, fH;
2325 PixelTransferResult fYTransfer;
2326 PixelTransferResult fUTransfer;
2327 PixelTransferResult fVTransfer;
2328 };
2329 // Assumption is that the caller would like to flush. We could take a parameter or require an
2330 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
2331 // callback to GrGpu until after the next flush that flushes our op list, though.
2332 auto* finishContext = new FinishContext{callback,
2333 context,
2334 dstW,
2335 dstH,
2336 std::move(yTransfer),
2337 std::move(uTransfer),
2338 std::move(vTransfer)};
2339 auto finishCallback = [](GrGpuFinishedContext c) {
2340 const auto* context = reinterpret_cast<const FinishContext*>(c);
2341 const void* y = context->fYTransfer.fTransferBuffer->map();
2342 const void* u = context->fUTransfer.fTransferBuffer->map();
2343 const void* v = context->fVTransfer.fTransferBuffer->map();
2344 if (!y || !u || !v) {
2345 if (y) {
2346 context->fYTransfer.fTransferBuffer->unmap();
2347 }
2348 if (u) {
2349 context->fUTransfer.fTransferBuffer->unmap();
2350 }
2351 if (v) {
2352 context->fVTransfer.fTransferBuffer->unmap();
2353 }
2354 (*context->fClientCallback)(context->fClientContext, nullptr, 0);
2355 delete context;
2356 return;
2357 }
2358 size_t w = SkToSizeT(context->fW);
2359 size_t h = SkToSizeT(context->fH);
2360 std::unique_ptr<uint8_t[]> yTemp;
2361 if (context->fYTransfer.fPixelConverter) {
2362 yTemp.reset(new uint8_t[w * h]);
2363 context->fYTransfer.fPixelConverter(yTemp.get(), y);
2364 y = yTemp.get();
2365 }
2366 std::unique_ptr<uint8_t[]> uTemp;
2367 if (context->fUTransfer.fPixelConverter) {
2368 uTemp.reset(new uint8_t[w / 2 * h / 2]);
2369 context->fUTransfer.fPixelConverter(uTemp.get(), u);
2370 u = uTemp.get();
2371 }
2372 std::unique_ptr<uint8_t[]> vTemp;
2373 if (context->fVTransfer.fPixelConverter) {
2374 vTemp.reset(new uint8_t[w / 2 * h / 2]);
2375 context->fVTransfer.fPixelConverter(vTemp.get(), v);
2376 v = vTemp.get();
2377 }
2378 const void* data[] = {y, u, v};
2379 size_t rowBytes[] = {w, w / 2, w / 2};
2380 (*context->fClientCallback)(context->fClientContext, data, rowBytes);
2381 context->fYTransfer.fTransferBuffer->unmap();
2382 context->fUTransfer.fTransferBuffer->unmap();
2383 context->fVTransfer.fTransferBuffer->unmap();
Brian Salomonab32f652019-05-10 14:24:50 -04002384 delete context;
2385 };
2386 GrFlushInfo flushInfo;
2387 flushInfo.fFinishedContext = finishContext;
2388 flushInfo.fFinishedProc = finishCallback;
2389 this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
Brian Salomonab32f652019-05-10 14:24:50 -04002390}
2391
Greg Daniele6bfb7d2019-04-17 15:26:11 -04002392GrSemaphoresSubmitted GrRenderTargetContext::flush(SkSurface::BackendSurfaceAccess access,
2393 const GrFlushInfo& info) {
robertphillips8c523e02016-07-26 07:41:00 -07002394 ASSERT_SINGLE_OWNER
Robert Phillips6a6de562019-02-15 15:19:15 -05002395 if (fContext->priv().abandoned()) {
Robert Phillipsa9162df2019-02-11 14:12:03 -05002396 return GrSemaphoresSubmitted::kNo;
2397 }
robertphillips8c523e02016-07-26 07:41:00 -07002398 SkDEBUGCODE(this->validate();)
Robert Phillips15c91422019-05-07 16:54:48 -04002399 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "flush", fContext);
robertphillips8c523e02016-07-26 07:41:00 -07002400
Greg Daniele6bfb7d2019-04-17 15:26:11 -04002401 return this->drawingManager()->flushSurface(fRenderTargetProxy.get(), access, info);
Greg Daniela5cb7812017-06-16 09:45:32 -04002402}
2403
Greg Danielc64ee462017-06-15 16:59:49 -04002404bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
Robert Phillipsbc4994a2019-02-14 08:36:56 -05002405 const GrBackendSemaphore waitSemaphores[]) {
Greg Daniela5cb7812017-06-16 09:45:32 -04002406 ASSERT_SINGLE_OWNER
Greg Danielc64ee462017-06-15 16:59:49 -04002407 RETURN_FALSE_IF_ABANDONED
Greg Daniela5cb7812017-06-16 09:45:32 -04002408 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04002409 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "waitOnSemaphores", fContext);
Greg Daniela5cb7812017-06-16 09:45:32 -04002410
2411 AutoCheckFlush acf(this->drawingManager());
2412
Brian Salomon9ff5acb2019-05-08 09:04:47 -04002413 if (numSemaphores && !this->caps()->semaphoreSupport()) {
Greg Danielc64ee462017-06-15 16:59:49 -04002414 return false;
2415 }
2416
Robert Phillipsbc4994a2019-02-14 08:36:56 -05002417 auto direct = fContext->priv().asDirectContext();
2418 if (!direct) {
2419 return false;
2420 }
2421
2422 auto resourceProvider = direct->priv().resourceProvider();
Robert Phillips6be756b2018-01-16 15:07:54 -05002423
Greg Daniela5cb7812017-06-16 09:45:32 -04002424 for (int i = 0; i < numSemaphores; ++i) {
Robert Phillips6be756b2018-01-16 15:07:54 -05002425 sk_sp<GrSemaphore> sema = resourceProvider->wrapBackendSemaphore(
Greg Daniel17b7c052018-01-09 13:55:33 -05002426 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
2427 kAdopt_GrWrapOwnership);
Robert Phillipsbc4994a2019-02-14 08:36:56 -05002428 std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(fContext, std::move(sema),
Robert Phillips7c525e62018-06-12 10:11:12 -04002429 fRenderTargetProxy.get()));
Greg Danielcb324152019-02-25 11:36:53 -05002430 this->getRTOpList()->addWaitOp(std::move(waitOp), *this->caps());
Greg Daniela5cb7812017-06-16 09:45:32 -04002431 }
Greg Danielc64ee462017-06-15 16:59:49 -04002432 return true;
robertphillips8c523e02016-07-26 07:41:00 -07002433}
joshualitt33a5fce2015-11-18 13:28:51 -08002434
Robert Phillips65a88fa2017-08-08 08:36:22 -04002435void GrRenderTargetContext::insertEventMarker(const SkString& str) {
Robert Phillips88a32ef2018-06-07 11:05:56 -04002436 std::unique_ptr<GrOp> op(GrDebugMarkerOp::Make(fContext, fRenderTargetProxy.get(), str));
Robert Phillips65a88fa2017-08-08 08:36:22 -04002437 this->getRTOpList()->addOp(std::move(op), *this->caps());
2438}
2439
Robert Phillipsbe9aff22019-02-15 11:33:22 -05002440const GrCaps* GrRenderTargetContext::caps() const {
2441 return fContext->priv().caps();
2442}
2443
Brian Osman11052242016-10-27 14:47:55 -04002444void GrRenderTargetContext::drawPath(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05002445 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002446 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04002447 const SkMatrix& viewMatrix,
Brian Salomon40b77a62017-12-22 11:25:52 -05002448 const SkPath& path,
Brian Osman11052242016-10-27 14:47:55 -04002449 const GrStyle& style) {
joshualitt1de610a2016-01-06 08:26:09 -08002450 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07002451 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07002452 SkDEBUGCODE(this->validate();)
Robert Phillips20390c32018-08-17 11:01:03 -04002453 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPath", fContext);
2454
Brian Salomon40b77a62017-12-22 11:25:52 -05002455 GrShape shape(path, style);
Robert Phillips20390c32018-08-17 11:01:03 -04002456
Robert Phillips27927a52018-08-20 13:18:12 -04002457 this->drawShape(clip, std::move(paint), aa, viewMatrix, shape);
Robert Phillips20390c32018-08-17 11:01:03 -04002458}
2459
2460void GrRenderTargetContext::drawShape(const GrClip& clip,
2461 GrPaint&& paint,
2462 GrAA aa,
2463 const SkMatrix& viewMatrix,
2464 const GrShape& shape) {
2465 ASSERT_SINGLE_OWNER
2466 RETURN_IF_ABANDONED
2467 SkDEBUGCODE(this->validate();)
2468 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawShape", fContext);
2469
Brian Salomon2fad74a2017-12-20 13:28:55 -05002470 if (shape.isEmpty()) {
2471 if (shape.inverseFilled()) {
2472 this->drawPaint(clip, std::move(paint), viewMatrix);
2473 }
2474 return;
robertphillipsea461502015-05-26 11:38:03 -07002475 }
2476
Robert Phillips72152832017-01-25 17:31:35 -05002477 AutoCheckFlush acf(this->drawingManager());
robertphillipsea461502015-05-26 11:38:03 -07002478
Brian Salomon2fad74a2017-12-20 13:28:55 -05002479 if (!shape.style().hasPathEffect()) {
Chris Dalton7d6748e2019-03-13 00:34:52 -06002480 GrAAType aaType = this->chooseAAType(aa);
Brian Salomon2fad74a2017-12-20 13:28:55 -05002481 SkRRect rrect;
2482 // We can ignore the starting point and direction since there is no path effect.
2483 bool inverted;
2484 if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) {
2485 if (rrect.isRect()) {
2486 this->drawRect(clip, std::move(paint), aa, viewMatrix, rrect.rect(),
2487 &shape.style());
2488 return;
2489 } else if (rrect.isOval()) {
2490 this->drawOval(clip, std::move(paint), aa, viewMatrix, rrect.rect(), shape.style());
robertphillipsea461502015-05-26 11:38:03 -07002491 return;
2492 }
Brian Salomon2fad74a2017-12-20 13:28:55 -05002493 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, shape.style());
2494 return;
Robert Phillips73653b42018-08-22 12:42:42 -04002495 } else if (GrAAType::kCoverage == aaType && shape.style().isSimpleFill() &&
2496 viewMatrix.rectStaysRect()) {
2497 // TODO: the rectStaysRect restriction could be lifted if we were willing to apply
2498 // the matrix to all the points individually rather than just to the rect
2499 SkRect rects[2];
2500 if (shape.asNestedRects(rects)) {
2501 // Concave AA paths are expensive - try to avoid them for special cases
Michael Ludwig72ab3462018-12-10 12:43:36 -05002502 std::unique_ptr<GrDrawOp> op = GrStrokeRectOp::MakeNested(
Robert Phillips73653b42018-08-22 12:42:42 -04002503 fContext, std::move(paint), viewMatrix, rects);
2504 if (op) {
2505 this->addDrawOp(clip, std::move(op));
2506 }
2507 // Returning here indicates that there is nothing to draw in this case.
2508 return;
2509 }
robertphillipsea461502015-05-26 11:38:03 -07002510 }
2511 }
robertphillips4bc31812016-03-01 12:22:49 -08002512
Brian Salomon2fad74a2017-12-20 13:28:55 -05002513 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape);
robertphillipsea461502015-05-26 11:38:03 -07002514}
2515
Chris Daltonbbfd5162017-11-07 13:35:22 -07002516bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
Brian Osman11052242016-10-27 14:47:55 -04002517 const GrUserStencilSettings* ss,
2518 SkRegion::Op op,
2519 bool invert,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002520 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04002521 const SkMatrix& viewMatrix,
2522 const SkPath& path) {
robertphillips391395d2016-03-02 09:26:36 -08002523 ASSERT_SINGLE_OWNER_PRIV
2524 RETURN_FALSE_IF_ABANDONED_PRIV
Brian Osman11052242016-10-27 14:47:55 -04002525 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04002526 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilPath",
2527 fRenderTargetContext->fContext);
robertphillips391395d2016-03-02 09:26:36 -08002528
2529 if (path.isEmpty() && path.isInverseFillType()) {
Michael Ludwigaa1b6b32019-05-29 14:43:13 -04002530 GrPaint paint;
2531 paint.setCoverageSetOpXPFactory(op, invert);
2532 this->stencilRect(clip, ss, std::move(paint), GrAA::kNo, SkMatrix::I(),
2533 SkRect::MakeIWH(fRenderTargetContext->width(),
2534 fRenderTargetContext->height()));
robertphillips391395d2016-03-02 09:26:36 -08002535 return true;
2536 }
2537
Robert Phillips72152832017-01-25 17:31:35 -05002538 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
robertphillips391395d2016-03-02 09:26:36 -08002539
2540 // An Assumption here is that path renderer would use some form of tweaking
2541 // the src color (either the input alpha or in the frag shader) to implement
2542 // aa. If we have some future driver-mojo path AA that can do the right
2543 // thing WRT to the blend then we'll need some query on the PR.
Chris Dalton09e56892019-03-13 00:22:01 -06002544 auto aaTypeFlags = choose_path_aa_type_flags(
2545 aa, fRenderTargetContext->fsaaType(), *fRenderTargetContext->caps());
robertphillips976f5f02016-06-03 10:59:20 -07002546 bool hasUserStencilSettings = !ss->isUnused();
robertphillips391395d2016-03-02 09:26:36 -08002547
Chris Daltondb91c6e2017-09-08 16:25:08 -06002548 SkIRect clipConservativeBounds;
2549 clip.getConservativeBounds(fRenderTargetContext->width(), fRenderTargetContext->height(),
2550 &clipConservativeBounds, nullptr);
2551
bsalomon8acedde2016-06-24 10:42:16 -07002552 GrShape shape(path, GrStyle::SimpleFill());
robertphillips391395d2016-03-02 09:26:36 -08002553 GrPathRenderer::CanDrawPathArgs canDrawArgs;
Brian Salomonc7fe0f72018-05-11 10:14:21 -04002554 canDrawArgs.fCaps = fRenderTargetContext->caps();
robertphillips391395d2016-03-02 09:26:36 -08002555 canDrawArgs.fViewMatrix = &viewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -07002556 canDrawArgs.fShape = &shape;
Chris Daltondb91c6e2017-09-08 16:25:08 -06002557 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
Chris Dalton09e56892019-03-13 00:22:01 -06002558 canDrawArgs.fAATypeFlags = aaTypeFlags;
Greg Danielbe7fc462019-01-03 16:40:42 -05002559 SkASSERT(!fRenderTargetContext->wrapsVkSecondaryCB());
2560 canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
cdalton93a379b2016-05-11 13:58:08 -07002561 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
robertphillips391395d2016-03-02 09:26:36 -08002562
2563 // Don't allow the SW renderer
Robert Phillips72152832017-01-25 17:31:35 -05002564 GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer(
Brian Salomon36aa1762016-12-10 13:24:02 -05002565 canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor);
robertphillips391395d2016-03-02 09:26:36 -08002566 if (!pr) {
2567 return false;
2568 }
2569
2570 GrPaint paint;
2571 paint.setCoverageSetOpXPFactory(op, invert);
2572
Brian Salomonf3569f02017-10-24 12:52:33 -04002573 GrPathRenderer::DrawPathArgs args{fRenderTargetContext->drawingManager()->getContext(),
2574 std::move(paint),
2575 ss,
2576 fRenderTargetContext,
2577 &clip,
2578 &clipConservativeBounds,
2579 &viewMatrix,
2580 &shape,
Chris Dalton09e56892019-03-13 00:22:01 -06002581 aaTypeFlags,
Brian Osman34ec3742018-07-03 10:40:57 -04002582 fRenderTargetContext->colorSpaceInfo().isLinearlyBlended()};
robertphillips391395d2016-03-02 09:26:36 -08002583 pr->drawPath(args);
2584 return true;
2585}
2586
Brian Osman11052242016-10-27 14:47:55 -04002587SkBudgeted GrRenderTargetContextPriv::isBudgeted() const {
robertphillips714712b2016-08-04 06:20:45 -07002588 ASSERT_SINGLE_OWNER_PRIV
2589
Robert Phillips6a6de562019-02-15 15:19:15 -05002590 if (fRenderTargetContext->fContext->priv().abandoned()) {
robertphillips714712b2016-08-04 06:20:45 -07002591 return SkBudgeted::kNo;
2592 }
2593
Brian Osman11052242016-10-27 14:47:55 -04002594 SkDEBUGCODE(fRenderTargetContext->validate();)
robertphillips714712b2016-08-04 06:20:45 -07002595
Robert Phillipsc7635fa2016-10-28 13:25:24 -04002596 return fRenderTargetContext->fRenderTargetProxy->isBudgeted();
robertphillips714712b2016-08-04 06:20:45 -07002597}
2598
Brian Salomon2fad74a2017-12-20 13:28:55 -05002599void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
2600 GrPaint&& paint,
2601 GrAA aa,
2602 const SkMatrix& viewMatrix,
2603 const GrShape& originalShape) {
joshualitt1de610a2016-01-06 08:26:09 -08002604 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07002605 RETURN_IF_ABANDONED
Brian Salomondcbb9d92017-07-19 10:53:20 -04002606 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext);
2607
Jim Van Verthf86073a2018-10-02 13:05:38 -04002608 if (!viewMatrix.isFinite() || !originalShape.bounds().isFinite()) {
2609 return;
2610 }
2611
Chris Daltondb91c6e2017-09-08 16:25:08 -06002612 SkIRect clipConservativeBounds;
2613 clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);
2614
Brian Salomon2fad74a2017-12-20 13:28:55 -05002615 GrShape tempShape;
Chris Dalton09e56892019-03-13 00:22:01 -06002616 auto aaTypeFlags = choose_path_aa_type_flags(aa, this->fsaaType(), *this->caps());
2617
robertphillips68737822015-10-29 12:12:21 -07002618 GrPathRenderer::CanDrawPathArgs canDrawArgs;
Brian Salomonc7fe0f72018-05-11 10:14:21 -04002619 canDrawArgs.fCaps = this->caps();
robertphillips68737822015-10-29 12:12:21 -07002620 canDrawArgs.fViewMatrix = &viewMatrix;
Brian Salomon2fad74a2017-12-20 13:28:55 -05002621 canDrawArgs.fShape = &originalShape;
Chris Daltondb91c6e2017-09-08 16:25:08 -06002622 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
Greg Danielbe7fc462019-01-03 16:40:42 -05002623 canDrawArgs.fTargetIsWrappedVkSecondaryCB = this->wrapsVkSecondaryCB();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002624 canDrawArgs.fHasUserStencilSettings = false;
robertphillips68737822015-10-29 12:12:21 -07002625
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002626 GrPathRenderer* pr;
Brian Salomon82125e92016-12-10 09:35:48 -05002627 static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor;
Brian Salomon2fad74a2017-12-20 13:28:55 -05002628 if (originalShape.isEmpty() && !originalShape.inverseFilled()) {
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002629 return;
2630 }
2631
Chris Dalton09e56892019-03-13 00:22:01 -06002632 canDrawArgs.fAATypeFlags = aaTypeFlags;
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002633
2634 // Try a 1st time without applying any of the style to the geometry (and barring sw)
2635 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
2636 SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix);
2637
Brian Salomon2fad74a2017-12-20 13:28:55 -05002638 if (!pr && originalShape.style().pathEffect()) {
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002639 // It didn't work above, so try again with the path effect applied.
Brian Salomon2fad74a2017-12-20 13:28:55 -05002640 tempShape = originalShape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
2641 if (tempShape.isEmpty()) {
robertphillipsea461502015-05-26 11:38:03 -07002642 return;
2643 }
Brian Salomon2fad74a2017-12-20 13:28:55 -05002644 canDrawArgs.fShape = &tempShape;
Robert Phillips72152832017-01-25 17:31:35 -05002645 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002646 }
2647 if (!pr) {
Brian Salomon2fad74a2017-12-20 13:28:55 -05002648 if (canDrawArgs.fShape->style().applies()) {
2649 tempShape = canDrawArgs.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec,
2650 styleScale);
2651 if (tempShape.isEmpty()) {
robertphillipsea461502015-05-26 11:38:03 -07002652 return;
2653 }
Brian Salomon2fad74a2017-12-20 13:28:55 -05002654 canDrawArgs.fShape = &tempShape;
Brian Salomone7df0bb2018-05-07 14:44:57 -04002655 // This time, allow SW renderer
2656 pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType);
2657 } else {
2658 pr = this->drawingManager()->getSoftwarePathRenderer();
bsalomon6663acf2016-05-10 09:14:17 -07002659 }
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002660 }
robertphillipsea461502015-05-26 11:38:03 -07002661
bsalomon8acedde2016-06-24 10:42:16 -07002662 if (!pr) {
robertphillipsea461502015-05-26 11:38:03 -07002663#ifdef SK_DEBUG
2664 SkDebugf("Unable to find path renderer compatible with path.\n");
2665#endif
2666 return;
2667 }
2668
Robert Phillips256c37b2017-03-01 14:32:46 -05002669 GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
Brian Salomon82f44312017-01-11 13:42:54 -05002670 std::move(paint),
2671 &GrUserStencilSettings::kUnused,
2672 this,
2673 &clip,
Chris Daltondb91c6e2017-09-08 16:25:08 -06002674 &clipConservativeBounds,
Brian Salomon82f44312017-01-11 13:42:54 -05002675 &viewMatrix,
Brian Salomon2fad74a2017-12-20 13:28:55 -05002676 canDrawArgs.fShape,
Chris Dalton09e56892019-03-13 00:22:01 -06002677 aaTypeFlags,
Brian Osman34ec3742018-07-03 10:40:57 -04002678 this->colorSpaceInfo().isLinearlyBlended()};
bsalomon0aff2fa2015-07-31 06:48:27 -07002679 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -07002680}
2681
Brian Salomon467921e2017-03-06 16:17:12 -05002682static void op_bounds(SkRect* bounds, const GrOp* op) {
2683 *bounds = op->bounds();
2684 if (op->hasZeroArea()) {
2685 if (op->hasAABloat()) {
2686 bounds->outset(0.5f, 0.5f);
2687 } else {
2688 // We don't know which way the particular GPU will snap lines or points at integer
2689 // coords. So we ensure that the bounds is large enough for either snap.
2690 SkRect before = *bounds;
2691 bounds->roundOut(bounds);
2692 if (bounds->fLeft == before.fLeft) {
2693 bounds->fLeft -= 1;
2694 }
2695 if (bounds->fTop == before.fTop) {
2696 bounds->fTop -= 1;
2697 }
2698 if (bounds->fRight == before.fRight) {
2699 bounds->fRight += 1;
2700 }
2701 if (bounds->fBottom == before.fBottom) {
2702 bounds->fBottom += 1;
2703 }
2704 }
2705 }
2706}
2707
Brian Salomon348a0372018-10-31 10:42:18 -04002708void GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op,
2709 const std::function<WillAddOpFn>& willAddFn) {
joshualitt1de610a2016-01-06 08:26:09 -08002710 ASSERT_SINGLE_OWNER
Robert Phillips69893702019-02-22 11:16:30 -05002711 if (fContext->priv().abandoned()) {
Robert Phillips9da87e02019-02-04 13:26:26 -05002712 fContext->priv().opMemoryPool()->release(std::move(op));
Brian Salomon348a0372018-10-31 10:42:18 -04002713 return;
Robert Phillipsc0138922017-03-08 11:50:55 -05002714 }
robertphillips2e1e51f2015-10-15 08:01:48 -07002715 SkDEBUGCODE(this->validate();)
Ethan Nicholas029b22c2018-10-18 16:49:56 -04002716 SkDEBUGCODE(op->fAddDrawOpCalled = true;)
Brian Salomondcbb9d92017-07-19 10:53:20 -04002717 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "addDrawOp", fContext);
robertphillips2d70dcb2015-10-06 07:38:23 -07002718
Brian Salomon467921e2017-03-06 16:17:12 -05002719 // Setup clip
2720 SkRect bounds;
2721 op_bounds(&bounds, op.get());
Brian Salomon97180af2017-03-14 13:42:58 -04002722 GrAppliedClip appliedClip;
Brian Salomon54d212e2017-03-21 14:22:38 -04002723 GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags();
2724 if (!clip.apply(fContext, this, fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA,
2725 fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil, &appliedClip,
2726 &bounds)) {
Robert Phillips9da87e02019-02-04 13:26:26 -05002727 fContext->priv().opMemoryPool()->release(std::move(op));
Brian Salomon348a0372018-10-31 10:42:18 -04002728 return;
Brian Salomon54d212e2017-03-21 14:22:38 -04002729 }
2730
Michael Ludwig6e17f1d2019-05-15 14:00:20 +00002731 if (fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil ||
2732 appliedClip.hasStencilClip()) {
2733 if (this->caps()->performStencilClearsAsDraws()) {
2734 // Must use an op to perform the clear of the stencil buffer before this op, but only
2735 // have to clear the first time any draw needs it (this also ensures we don't loop
2736 // forever when the internal stencil clear adds a draw op that has stencil settings).
2737 if (!fRenderTargetProxy->needsStencil()) {
2738 // Send false so that the stencil buffer is fully cleared to 0
Michael Ludwigc39d0c82019-01-15 10:03:43 -05002739 this->internalStencilClear(GrFixedClip::Disabled(), /* inside mask */ false);
2740 }
Michael Ludwig6e17f1d2019-05-15 14:00:20 +00002741 } else {
2742 // Just make sure the stencil buffer is cleared before the draw op, easy to do it as
2743 // a load at the start
2744 this->getRTOpList()->setStencilLoadOp(GrLoadOp::kClear);
Michael Ludwigc39d0c82019-01-15 10:03:43 -05002745 }
Robert Phillips95214472017-08-08 18:00:03 -04002746
Robert Phillips65048132017-08-10 08:44:49 -04002747 this->setNeedsStencil();
Brian Salomon54d212e2017-03-21 14:22:38 -04002748 }
2749
Brian Osman5ced0bf2019-03-15 10:15:29 -04002750 GrClampType clampType = GrPixelConfigClampType(this->colorSpaceInfo().config());
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002751 GrXferProcessor::DstProxy dstProxy;
Brian Osman5ced0bf2019-03-15 10:15:29 -04002752 GrProcessorSet::Analysis analysis = op->finalize(
2753 *this->caps(), &appliedClip, this->fsaaType(), clampType);
Chris Dalton945ee652019-01-23 09:10:36 -07002754 if (analysis.requiresDstTexture()) {
Brian Salomon09181ef2018-11-14 13:39:51 -05002755 if (!this->setupDstProxy(this->asRenderTargetProxy(), clip, *op, &dstProxy)) {
Robert Phillips9da87e02019-02-04 13:26:26 -05002756 fContext->priv().opMemoryPool()->release(std::move(op));
Brian Salomon348a0372018-10-31 10:42:18 -04002757 return;
Brian Salomon54d212e2017-03-21 14:22:38 -04002758 }
2759 }
2760
2761 op->setClippedBounds(bounds);
Brian Salomon348a0372018-10-31 10:42:18 -04002762 auto opList = this->getRTOpList();
2763 if (willAddFn) {
2764 willAddFn(op.get(), opList->uniqueID());
2765 }
Chris Dalton945ee652019-01-23 09:10:36 -07002766 opList->addDrawOp(std::move(op), analysis, std::move(appliedClip), dstProxy, *this->caps());
Brian Salomon54d212e2017-03-21 14:22:38 -04002767}
2768
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002769bool GrRenderTargetContext::setupDstProxy(GrRenderTargetProxy* rtProxy, const GrClip& clip,
Brian Salomon09181ef2018-11-14 13:39:51 -05002770 const GrOp& op,
Robert Phillips16d8ec62017-07-27 16:16:25 -04002771 GrXferProcessor::DstProxy* dstProxy) {
Greg Danielbe7fc462019-01-03 16:40:42 -05002772 // If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we
2773 // don't actually have a VkImage to make a copy of. Additionally we don't have the power to
2774 // start and stop the render pass in order to make the copy.
2775 if (rtProxy->wrapsVkSecondaryCB()) {
2776 return false;
2777 }
2778
Brian Salomon467921e2017-03-06 16:17:12 -05002779 if (this->caps()->textureBarrierSupport()) {
Robert Phillipsbf25d432017-04-07 10:08:53 -04002780 if (GrTextureProxy* texProxy = rtProxy->asTextureProxy()) {
Brian Salomon467921e2017-03-06 16:17:12 -05002781 // The render target is a texture, so we can read from it directly in the shader. The XP
2782 // will be responsible to detect this situation and request a texture barrier.
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002783 dstProxy->setProxy(sk_ref_sp(texProxy));
2784 dstProxy->setOffset(0, 0);
Robert Phillipsbf25d432017-04-07 10:08:53 -04002785 return true;
Brian Salomon467921e2017-03-06 16:17:12 -05002786 }
2787 }
2788
Robert Phillipsbf25d432017-04-07 10:08:53 -04002789 SkIRect copyRect = SkIRect::MakeWH(rtProxy->width(), rtProxy->height());
Brian Salomon467921e2017-03-06 16:17:12 -05002790
Eric Karl74480882017-04-03 14:49:05 -07002791 SkIRect clippedRect;
Robert Phillipsbf25d432017-04-07 10:08:53 -04002792 clip.getConservativeBounds(rtProxy->width(), rtProxy->height(), &clippedRect);
Brian Salomon09181ef2018-11-14 13:39:51 -05002793 SkRect opBounds = op.bounds();
2794 // If the op has aa bloating or is a infinitely thin geometry (hairline) outset the bounds by
2795 // 0.5 pixels.
2796 if (op.hasAABloat() || op.hasZeroArea()) {
2797 opBounds.outset(0.5f, 0.5f);
2798 // An antialiased/hairline draw can sometimes bleed outside of the clips bounds. For
2799 // performance we may ignore the clip when the draw is entirely inside the clip is float
2800 // space but will hit pixels just outside the clip when actually rasterizing.
2801 clippedRect.outset(1, 1);
2802 clippedRect.intersect(SkIRect::MakeWH(rtProxy->width(), rtProxy->height()));
2803 }
2804 SkIRect opIBounds;
2805 opBounds.roundOut(&opIBounds);
2806 if (!clippedRect.intersect(opIBounds)) {
Brian Salomon467921e2017-03-06 16:17:12 -05002807#ifdef SK_DEBUG
Robert Phillipsbf25d432017-04-07 10:08:53 -04002808 GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw.");
Brian Salomon467921e2017-03-06 16:17:12 -05002809#endif
Robert Phillipsbf25d432017-04-07 10:08:53 -04002810 return false;
Brian Salomon467921e2017-03-06 16:17:12 -05002811 }
2812
2813 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
2814 // have per-sample dst values by making the copy multisampled.
2815 GrSurfaceDesc desc;
Eric Karl74480882017-04-03 14:49:05 -07002816 bool rectsMustMatch = false;
2817 bool disallowSubrect = false;
Greg Daniel46cfbc62019-06-07 11:43:30 -04002818 if (!this->caps()->initDescForDstCopy(rtProxy, &desc, &rectsMustMatch,
Brian Salomon2a4f9832018-03-03 22:43:43 -05002819 &disallowSubrect)) {
Brian Salomon467921e2017-03-06 16:17:12 -05002820 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillipsbf25d432017-04-07 10:08:53 -04002821 desc.fConfig = rtProxy->config();
Brian Salomon467921e2017-03-06 16:17:12 -05002822 }
2823
Eric Karl74480882017-04-03 14:49:05 -07002824 if (!disallowSubrect) {
2825 copyRect = clippedRect;
2826 }
Brian Salomon467921e2017-03-06 16:17:12 -05002827
Robert Phillipsbf25d432017-04-07 10:08:53 -04002828 SkIPoint dstPoint, dstOffset;
2829 SkBackingFit fit;
Greg Daniel46cfbc62019-06-07 11:43:30 -04002830 GrSurfaceProxy::RectsMustMatch matchRects;
Eric Karl74480882017-04-03 14:49:05 -07002831 if (rectsMustMatch) {
Robert Phillipsbf25d432017-04-07 10:08:53 -04002832 desc.fWidth = rtProxy->width();
2833 desc.fHeight = rtProxy->height();
Eric Karl74480882017-04-03 14:49:05 -07002834 dstPoint = {copyRect.fLeft, copyRect.fTop};
2835 dstOffset = {0, 0};
Robert Phillipsbf25d432017-04-07 10:08:53 -04002836 fit = SkBackingFit::kExact;
Greg Daniel46cfbc62019-06-07 11:43:30 -04002837 matchRects = GrSurfaceProxy::RectsMustMatch::kYes;
Eric Karl74480882017-04-03 14:49:05 -07002838 } else {
2839 desc.fWidth = copyRect.width();
2840 desc.fHeight = copyRect.height();
2841 dstPoint = {0, 0};
2842 dstOffset = {copyRect.fLeft, copyRect.fTop};
Robert Phillipsbf25d432017-04-07 10:08:53 -04002843 fit = SkBackingFit::kApprox;
Greg Daniel46cfbc62019-06-07 11:43:30 -04002844 matchRects = GrSurfaceProxy::RectsMustMatch::kNo;
Eric Karl74480882017-04-03 14:49:05 -07002845 }
Brian Salomon467921e2017-03-06 16:17:12 -05002846
Greg Daniel46cfbc62019-06-07 11:43:30 -04002847 sk_sp<GrTextureProxy> newProxy = GrSurfaceProxy::Copy(fContext, rtProxy, GrMipMapped::kNo,
2848 copyRect, fit, SkBudgeted::kYes,
2849 matchRects);
2850 SkASSERT(newProxy);
Robert Phillipsbf25d432017-04-07 10:08:53 -04002851
Greg Daniel46cfbc62019-06-07 11:43:30 -04002852 dstProxy->setProxy(std::move(newProxy));
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002853 dstProxy->setOffset(dstOffset);
Robert Phillipsbf25d432017-04-07 10:08:53 -04002854 return true;
robertphillips2334fb62015-06-17 05:43:33 -07002855}
Greg Daniel46cfbc62019-06-07 11:43:30 -04002856
2857bool GrRenderTargetContext::blitTexture(GrTextureProxy* src, const SkIRect& srcRect,
2858 const SkIPoint& dstPoint) {
2859 SkIRect clippedSrcRect;
2860 SkIPoint clippedDstPoint;
2861 if (!GrClipSrcRectAndDstPoint(this->asSurfaceProxy()->isize(), src->isize(), srcRect, dstPoint,
2862 &clippedSrcRect, &clippedDstPoint)) {
2863 return false;
2864 }
2865
2866 GrPaint paint;
2867 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
2868 auto fp = GrSimpleTextureEffect::Make(sk_ref_sp(src->asTextureProxy()),
2869 SkMatrix::I());
2870 if (!fp) {
2871 return false;
2872 }
2873 paint.addColorFragmentProcessor(std::move(fp));
2874
2875 this->fillRectToRect(
2876 GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
2877 SkRect::MakeXYWH(clippedDstPoint.fX, clippedDstPoint.fY, clippedSrcRect.width(),
2878 clippedSrcRect.height()),
2879 SkRect::Make(clippedSrcRect));
2880 return true;
2881}
2882