1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/GrRenderTargetContext.h"
9
10 #include "include/core/SkDrawable.h"
11 #include "include/gpu/GrBackendSemaphore.h"
12 #include "include/private/GrRecordingContext.h"
13 #include "include/private/SkShadowFlags.h"
14 #include "include/utils/SkShadowUtils.h"
15 #include "src/core/SkAutoPixmapStorage.h"
16 #include "src/core/SkConvertPixels.h"
17 #include "src/core/SkDrawShadowInfo.h"
18 #include "src/core/SkGlyphRunPainter.h"
19 #include "src/core/SkLatticeIter.h"
20 #include "src/core/SkMakeUnique.h"
21 #include "src/core/SkMatrixPriv.h"
22 #include "src/core/SkRRectPriv.h"
23 #include "src/core/SkSurfacePriv.h"
24 #include "src/gpu/GrAppliedClip.h"
25 #include "src/gpu/GrAuditTrail.h"
26 #include "src/gpu/GrBlurUtils.h"
27 #include "src/gpu/GrCaps.h"
28 #include "src/gpu/GrClientMappedBufferManager.h"
29 #include "src/gpu/GrColor.h"
30 #include "src/gpu/GrContextPriv.h"
31 #include "src/gpu/GrDataUtils.h"
32 #include "src/gpu/GrDrawingManager.h"
33 #include "src/gpu/GrFixedClip.h"
34 #include "src/gpu/GrGpuResourcePriv.h"
35 #include "src/gpu/GrImageInfo.h"
36 #include "src/gpu/GrMemoryPool.h"
37 #include "src/gpu/GrPathRenderer.h"
38 #include "src/gpu/GrRecordingContextPriv.h"
39 #include "src/gpu/GrRenderTarget.h"
40 #include "src/gpu/GrRenderTargetContextPriv.h"
41 #include "src/gpu/GrResourceProvider.h"
42 #include "src/gpu/GrStencilAttachment.h"
43 #include "src/gpu/GrStyle.h"
44 #include "src/gpu/GrTracing.h"
45 #include "src/gpu/SkGr.h"
46 #include "src/gpu/effects/GrBicubicEffect.h"
47 #include "src/gpu/effects/GrRRectEffect.h"
48 #include "src/gpu/effects/GrTextureDomain.h"
49 #include "src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h"
50 #include "src/gpu/geometry/GrQuad.h"
51 #include "src/gpu/geometry/GrQuadUtils.h"
52 #include "src/gpu/geometry/GrShape.h"
53 #include "src/gpu/ops/GrAtlasTextOp.h"
54 #include "src/gpu/ops/GrClearOp.h"
55 #include "src/gpu/ops/GrClearStencilClipOp.h"
56 #include "src/gpu/ops/GrDebugMarkerOp.h"
57 #include "src/gpu/ops/GrDrawAtlasOp.h"
58 #include "src/gpu/ops/GrDrawOp.h"
59 #include "src/gpu/ops/GrDrawVerticesOp.h"
60 #include "src/gpu/ops/GrDrawableOp.h"
61 #include "src/gpu/ops/GrFillRRectOp.h"
62 #include "src/gpu/ops/GrFillRectOp.h"
63 #include "src/gpu/ops/GrLatticeOp.h"
64 #include "src/gpu/ops/GrOp.h"
65 #include "src/gpu/ops/GrOvalOpFactory.h"
66 #include "src/gpu/ops/GrRegionOp.h"
67 #include "src/gpu/ops/GrShadowRRectOp.h"
68 #include "src/gpu/ops/GrStencilPathOp.h"
69 #include "src/gpu/ops/GrStrokeRectOp.h"
70 #include "src/gpu/ops/GrTextureOp.h"
71 #include "src/gpu/text/GrTextContext.h"
72 #include "src/gpu/text/GrTextTarget.h"
73
74 class GrRenderTargetContext::TextTarget : public GrTextTarget {
75 public:
TextTarget(GrRenderTargetContext * renderTargetContext)76 TextTarget(GrRenderTargetContext* renderTargetContext)
77 : GrTextTarget(renderTargetContext->width(), renderTargetContext->height(),
78 renderTargetContext->colorInfo())
79 , fRenderTargetContext(renderTargetContext)
80 , fGlyphPainter{*renderTargetContext} {}
81
addDrawOp(const GrClip & clip,std::unique_ptr<GrAtlasTextOp> op)82 void addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) override {
83 fRenderTargetContext->addDrawOp(clip, std::move(op));
84 }
85
drawShape(const GrClip & clip,const SkPaint & paint,const SkMatrix & viewMatrix,const GrShape & shape)86 void drawShape(const GrClip& clip, const SkPaint& paint,
87 const SkMatrix& viewMatrix, const GrShape& shape) override {
88 GrBlurUtils::drawShapeWithMaskFilter(fRenderTargetContext->fContext, fRenderTargetContext,
89 clip, paint, viewMatrix, shape);
90 }
91
makeGrPaint(GrMaskFormat maskFormat,const SkPaint & skPaint,const SkMatrix & viewMatrix,GrPaint * grPaint)92 void makeGrPaint(GrMaskFormat maskFormat, const SkPaint& skPaint, const SkMatrix& viewMatrix,
93 GrPaint* grPaint) override {
94 auto context = fRenderTargetContext->fContext;
95 const GrColorInfo& colorInfo = fRenderTargetContext->colorInfo();
96 if (kARGB_GrMaskFormat == maskFormat) {
97 SkPaintToGrPaintWithPrimitiveColor(context, colorInfo, skPaint, grPaint);
98 } else {
99 SkPaintToGrPaint(context, colorInfo, skPaint, viewMatrix, grPaint);
100 }
101 }
102
getContext()103 GrRecordingContext* getContext() override {
104 return fRenderTargetContext->fContext;
105 }
106
glyphPainter()107 SkGlyphRunListPainter* glyphPainter() override {
108 return &fGlyphPainter;
109 }
110
111 private:
112 GrRenderTargetContext* fRenderTargetContext;
113 SkGlyphRunListPainter fGlyphPainter;
114
115 };
116
117 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
118 #define ASSERT_SINGLE_OWNER \
119 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
120 #define ASSERT_SINGLE_OWNER_PRIV \
121 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());)
122 #define RETURN_IF_ABANDONED if (fContext->priv().abandoned()) { return; }
123 #define RETURN_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return; }
124 #define RETURN_FALSE_IF_ABANDONED if (fContext->priv().abandoned()) { return false; }
125 #define RETURN_FALSE_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return false; }
126 #define RETURN_NULL_IF_ABANDONED if (fContext->priv().abandoned()) { return nullptr; }
127
128 //////////////////////////////////////////////////////////////////////////////
129
130 class AutoCheckFlush {
131 public:
AutoCheckFlush(GrDrawingManager * drawingManager)132 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
133 SkASSERT(fDrawingManager);
134 }
~AutoCheckFlush()135 ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
136
137 private:
138 GrDrawingManager* fDrawingManager;
139 };
140
141 // In MDB mode the reffing of the 'getLastOpsTask' call's result allows in-progress
142 // GrOpsTask to be picked up and added to by renderTargetContexts lower in the call
143 // stack. When this occurs with a closed GrOpsTask, a new one will be allocated
144 // when the renderTargetContext attempts to use it (via getOpsTask).
GrRenderTargetContext(GrRecordingContext * context,sk_sp<GrRenderTargetProxy> rtp,GrColorType colorType,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps,bool managedOpsTask)145 GrRenderTargetContext::GrRenderTargetContext(GrRecordingContext* context,
146 sk_sp<GrRenderTargetProxy> rtp,
147 GrColorType colorType,
148 sk_sp<SkColorSpace> colorSpace,
149 const SkSurfaceProps* surfaceProps,
150 bool managedOpsTask)
151 : GrSurfaceContext(context, colorType, kPremul_SkAlphaType, std::move(colorSpace))
152 , fRenderTargetProxy(std::move(rtp))
153 , fOpsTask(sk_ref_sp(fRenderTargetProxy->getLastOpsTask()))
154 , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
155 , fManagedOpsTask(managedOpsTask) {
156 fTextTarget.reset(new TextTarget(this));
157 SkDEBUGCODE(this->validate();)
158 }
159
160 #ifdef SK_DEBUG
validate() const161 void GrRenderTargetContext::validate() const {
162 SkASSERT(fRenderTargetProxy);
163 fRenderTargetProxy->validate(fContext);
164
165 SkASSERT(fContext->priv().caps()->areColorTypeAndFormatCompatible(
166 this->colorInfo().colorType(), fRenderTargetProxy->backendFormat()));
167
168 if (fOpsTask && !fOpsTask->isClosed()) {
169 SkASSERT(fRenderTargetProxy->getLastRenderTask() == fOpsTask.get());
170 }
171 }
172 #endif
173
~GrRenderTargetContext()174 GrRenderTargetContext::~GrRenderTargetContext() {
175 ASSERT_SINGLE_OWNER
176 }
177
chooseAAType(GrAA aa)178 inline GrAAType GrRenderTargetContext::chooseAAType(GrAA aa) {
179 if (GrAA::kNo == aa) {
180 // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
181 // that.
182 if (this->numSamples() > 1 && !this->caps()->multisampleDisableSupport()) {
183 return GrAAType::kMSAA;
184 }
185 return GrAAType::kNone;
186 }
187 return (this->numSamples() > 1) ? GrAAType::kMSAA : GrAAType::kCoverage;
188 }
189
asTextureProxy()190 GrTextureProxy* GrRenderTargetContext::asTextureProxy() {
191 return fRenderTargetProxy->asTextureProxy();
192 }
193
asTextureProxy() const194 const GrTextureProxy* GrRenderTargetContext::asTextureProxy() const {
195 return fRenderTargetProxy->asTextureProxy();
196 }
197
asTextureProxyRef()198 sk_sp<GrTextureProxy> GrRenderTargetContext::asTextureProxyRef() {
199 return sk_ref_sp(fRenderTargetProxy->asTextureProxy());
200 }
201
mipMapped() const202 GrMipMapped GrRenderTargetContext::mipMapped() const {
203 if (const GrTextureProxy* proxy = this->asTextureProxy()) {
204 return proxy->mipMapped();
205 }
206 return GrMipMapped::kNo;
207 }
208
getOpsTask()209 GrOpsTask* GrRenderTargetContext::getOpsTask() {
210 ASSERT_SINGLE_OWNER
211 SkDEBUGCODE(this->validate();)
212
213 if (!fOpsTask || fOpsTask->isClosed()) {
214 sk_sp<GrOpsTask> newOpsTask =
215 this->drawingManager()->newOpsTask(fRenderTargetProxy, fManagedOpsTask);
216 if (fOpsTask && fNumStencilSamples > 0) {
217 // Store the stencil values in memory upon completion of fOpsTask.
218 fOpsTask->setMustPreserveStencil();
219 // Reload the stencil buffer content at the beginning of newOpsTask.
220 // FIXME: Could the topo sort insert a task between these two that modifies the stencil
221 // values?
222 newOpsTask->setInitialStencilContent(GrOpsTask::StencilContent::kPreserved);
223 }
224 fOpsTask = std::move(newOpsTask);
225 }
226
227 return fOpsTask.get();
228 }
229
drawGlyphRunList(const GrClip & clip,const SkMatrix & viewMatrix,const SkGlyphRunList & blob)230 void GrRenderTargetContext::drawGlyphRunList(
231 const GrClip& clip, const SkMatrix& viewMatrix,
232 const SkGlyphRunList& blob) {
233 ASSERT_SINGLE_OWNER
234 RETURN_IF_ABANDONED
235 SkDEBUGCODE(this->validate();)
236 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawGlyphRunList", fContext);
237
238 // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
239 // secondary command buffers because it would require stopping and starting a render pass which
240 // we don't have access to.
241 if (this->wrapsVkSecondaryCB()) {
242 return;
243 }
244
245 GrTextContext* atlasTextContext = this->drawingManager()->getTextContext();
246 atlasTextContext->drawGlyphRunList(fContext, fTextTarget.get(), clip, viewMatrix,
247 fSurfaceProps, blob);
248 }
249
discard()250 void GrRenderTargetContext::discard() {
251 ASSERT_SINGLE_OWNER
252 RETURN_IF_ABANDONED
253 SkDEBUGCODE(this->validate();)
254 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "discard", fContext);
255
256 AutoCheckFlush acf(this->drawingManager());
257
258 this->getOpsTask()->discard();
259 }
260
clear(const SkIRect * rect,const SkPMColor4f & color,CanClearFullscreen canClearFullscreen)261 void GrRenderTargetContext::clear(const SkIRect* rect,
262 const SkPMColor4f& color,
263 CanClearFullscreen canClearFullscreen) {
264 ASSERT_SINGLE_OWNER
265 RETURN_IF_ABANDONED
266 SkDEBUGCODE(this->validate();)
267 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "clear", fContext);
268
269 AutoCheckFlush acf(this->drawingManager());
270 this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color,
271 canClearFullscreen);
272 }
273
clear(const GrFixedClip & clip,const SkPMColor4f & color,CanClearFullscreen canClearFullscreen)274 void GrRenderTargetContextPriv::clear(const GrFixedClip& clip,
275 const SkPMColor4f& color,
276 CanClearFullscreen canClearFullscreen) {
277 ASSERT_SINGLE_OWNER_PRIV
278 RETURN_IF_ABANDONED_PRIV
279 SkDEBUGCODE(fRenderTargetContext->validate();)
280 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clear",
281 fRenderTargetContext->fContext);
282
283 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
284 fRenderTargetContext->internalClear(clip, color, canClearFullscreen);
285 }
286
clear_to_grpaint(const SkPMColor4f & color,GrPaint * paint)287 static void clear_to_grpaint(const SkPMColor4f& color, GrPaint* paint) {
288 paint->setColor4f(color);
289 if (color.isOpaque()) {
290 // Can just rely on the src-over blend mode to do the right thing
291 paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
292 } else {
293 // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
294 // were src blended
295 paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
296 }
297 }
298
internalClear(const GrFixedClip & clip,const SkPMColor4f & color,CanClearFullscreen canClearFullscreen)299 void GrRenderTargetContext::internalClear(const GrFixedClip& clip,
300 const SkPMColor4f& color,
301 CanClearFullscreen canClearFullscreen) {
302 bool isFull = false;
303 if (!clip.hasWindowRectangles()) {
304 // TODO: wrt the shouldInitializeTextures path, it would be more performant to
305 // only clear the entire target if we knew it had not been cleared before. As
306 // is this could end up doing a lot of redundant clears.
307 isFull = !clip.scissorEnabled() ||
308 (CanClearFullscreen::kYes == canClearFullscreen &&
309 (this->caps()->preferFullscreenClears() || this->caps()->shouldInitializeTextures())) ||
310 clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
311 }
312
313 if (isFull) {
314 GrOpsTask* opsTask = this->getOpsTask();
315 if (opsTask->resetForFullscreenClear(this->canDiscardPreviousOpsOnFullClear()) &&
316 !this->caps()->performColorClearsAsDraws()) {
317 // The op list was emptied and native clears are allowed, so just use the load op
318 opsTask->setColorLoadOp(GrLoadOp::kClear, color);
319 return;
320 } else {
321 // Will use an op for the clear, reset the load op to discard since the op will
322 // blow away the color buffer contents
323 opsTask->setColorLoadOp(GrLoadOp::kDiscard);
324 }
325
326 // Must add an op to the list (either because we couldn't use a load op, or because the
327 // clear load op isn't supported)
328 if (this->caps()->performColorClearsAsDraws()) {
329 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
330 GrPaint paint;
331 clear_to_grpaint(color, &paint);
332 this->addDrawOp(GrFixedClip::Disabled(),
333 GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
334 rtRect));
335 } else {
336 this->addOp(GrClearOp::Make(
337 fContext, SkIRect::MakeEmpty(), color, /* fullscreen */ true));
338 }
339 } else {
340 if (this->caps()->performPartialClearsAsDraws()) {
341 // performPartialClearsAsDraws() also returns true if any clear has to be a draw.
342 GrPaint paint;
343 clear_to_grpaint(color, &paint);
344
345 this->addDrawOp(clip,
346 GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
347 SkRect::Make(clip.scissorRect())));
348 } else {
349 std::unique_ptr<GrOp> op(GrClearOp::Make(fContext, clip, color,
350 this->asSurfaceProxy()));
351 // This version of the clear op factory can return null if the clip doesn't intersect
352 // with the surface proxy's boundary
353 if (!op) {
354 return;
355 }
356 this->addOp(std::move(op));
357 }
358 }
359 }
360
drawPaint(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix)361 void GrRenderTargetContext::drawPaint(const GrClip& clip,
362 GrPaint&& paint,
363 const SkMatrix& viewMatrix) {
364 // Start with the render target, since that is the maximum content we could possibly fill.
365 // drawFilledQuad() will automatically restrict it to clip bounds for us if possible.
366 SkRect r = fRenderTargetProxy->getBoundsRect();
367 if (!paint.numTotalFragmentProcessors()) {
368 // The paint is trivial so we won't need to use local coordinates, so skip calculating the
369 // inverse view matrix.
370 this->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), r, r);
371 } else {
372 // Use the inverse view matrix to arrive at appropriate local coordinates for the paint.
373 SkMatrix localMatrix;
374 if (!viewMatrix.invert(&localMatrix)) {
375 return;
376 }
377 this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), r,
378 localMatrix);
379 }
380 }
381
382 enum class GrRenderTargetContext::QuadOptimization {
383 // The rect to draw doesn't intersect clip or render target, so no draw op should be added
384 kDiscarded,
385 // The rect to draw was converted to some other op and appended to the oplist, so no additional
386 // op is necessary. Currently this can convert it to a clear op or a rrect op. Only valid if
387 // a constColor is provided.
388 kSubmitted,
389 // The clip was folded into the device quad, with updated edge flags and local coords, and
390 // caller is responsible for adding an appropriate op.
391 kClipApplied,
392 // No change to clip, but quad updated to better fit clip/render target, and caller is
393 // responsible for adding an appropriate op.
394 kCropped
395 };
396
make_vertex_finite(float * value)397 static bool make_vertex_finite(float* value) {
398 if (SkScalarIsNaN(*value)) {
399 return false;
400 }
401
402 if (!SkScalarIsFinite(*value)) {
403 // +/- infinity at this point. Don't use exactly SK_ScalarMax so that we have some precision
404 // left when calculating crops.
405 static constexpr float kNearInfinity = SK_ScalarMax / 4.f;
406 *value = *value < 0.f ? -kNearInfinity : kNearInfinity;
407 }
408
409 return true;
410 }
411
attemptQuadOptimization(const GrClip & clip,const SkPMColor4f * constColor,const GrUserStencilSettings * stencilSettings,GrAA * aa,GrQuadAAFlags * edgeFlags,GrQuad * deviceQuad,GrQuad * localQuad)412 GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimization(
413 const GrClip& clip, const SkPMColor4f* constColor,
414 const GrUserStencilSettings* stencilSettings, GrAA* aa, GrQuadAAFlags* edgeFlags,
415 GrQuad* deviceQuad, GrQuad* localQuad) {
416 // Optimization requirements:
417 // 1. kDiscard applies when clip bounds and quad bounds do not intersect
418 // 2. kClear applies when constColor and final geom is pixel aligned rect;
419 // pixel aligned rect requires rect clip and (rect quad or quad covers clip)
420 // 3. kRRect applies when constColor and rrect clip and quad covers clip
421 // 4. kExplicitClip applies when rect clip and (rect quad or quad covers clip)
422 // 5. kCropped applies when rect quad (currently)
423 // 6. kNone always applies
424 GrQuadAAFlags newFlags = *edgeFlags;
425
426 SkRect rtRect;
427 if (stencilSettings) {
428 // Must use worst case bounds so that stencil buffer updates on approximately sized render
429 // targets don't get corrupted.
430 rtRect = SkRect::MakeWH(fRenderTargetProxy->worstCaseWidth(),
431 fRenderTargetProxy->worstCaseHeight());
432 } else {
433 // Use the logical size of the render target, which allows for "fullscreen" clears even if
434 // the render target has an approximate backing fit
435 rtRect = SkRect::MakeWH(this->width(), this->height());
436 }
437
438 SkRect drawBounds = deviceQuad->bounds();
439 if (constColor) {
440 // Don't bother updating local coordinates when the paint will ignore them anyways
441 localQuad = nullptr;
442 // If the device quad is not finite, coerce into a finite quad. This is acceptable since it
443 // will be cropped to the finite 'clip' or render target and there is no local space mapping
444 if (!deviceQuad->isFinite()) {
445 for (int i = 0; i < 4; ++i) {
446 if (!make_vertex_finite(deviceQuad->xs() + i) ||
447 !make_vertex_finite(deviceQuad->ys() + i) ||
448 !make_vertex_finite(deviceQuad->ws() + i)) {
449 // Discard if we see a nan
450 return QuadOptimization::kDiscarded;
451 }
452 }
453 SkASSERT(deviceQuad->isFinite());
454 }
455 } else {
456 // CropToRect requires the quads to be finite. If they are not finite and we have local
457 // coordinates, the mapping from local space to device space is poorly defined so drop it
458 if (!deviceQuad->isFinite()) {
459 return QuadOptimization::kDiscarded;
460 }
461 }
462
463 // If the quad is entirely off screen, it doesn't matter what the clip does
464 if (!rtRect.intersects(drawBounds)) {
465 return QuadOptimization::kDiscarded;
466 }
467
468 // Check if clip can be represented as a rounded rect (initialize as if clip fully contained
469 // the render target).
470 SkRRect clipRRect = SkRRect::MakeRect(rtRect);
471 // We initialize clipAA to *aa when there are stencil settings so that we don't artificially
472 // encounter mixed-aa edges (not allowed for stencil), but we want to start as non-AA for
473 // regular draws so that if we fully cover the render target, that can stop being anti-aliased.
474 GrAA clipAA = stencilSettings ? *aa : GrAA::kNo;
475 bool axisAlignedClip = true;
476 if (!clip.quickContains(rtRect)) {
477 if (!clip.isRRect(rtRect, &clipRRect, &clipAA)) {
478 axisAlignedClip = false;
479 }
480 }
481
482 // If the clip rrect is valid (i.e. axis-aligned), we can potentially combine it with the
483 // draw geometry so that no clip is needed when drawing.
484 if (axisAlignedClip && (!stencilSettings || clipAA == *aa)) {
485 // Tighten clip bounds (if clipRRect.isRect() is true, clipBounds now holds the intersection
486 // of the render target and the clip rect)
487 SkRect clipBounds = rtRect;
488 if (!clipBounds.intersect(clipRRect.rect()) || !clipBounds.intersects(drawBounds)) {
489 return QuadOptimization::kDiscarded;
490 }
491
492 if (clipRRect.isRect()) {
493 // No rounded corners, so the kClear and kExplicitClip optimizations are possible
494 if (GrQuadUtils::CropToRect(clipBounds, clipAA, &newFlags, deviceQuad, localQuad)) {
495 if (constColor && deviceQuad->quadType() == GrQuad::Type::kAxisAligned) {
496 // Clear optimization is possible
497 drawBounds = deviceQuad->bounds();
498 if (drawBounds.contains(rtRect)) {
499 // Fullscreen clear
500 this->clear(nullptr, *constColor, CanClearFullscreen::kYes);
501 return QuadOptimization::kSubmitted;
502 } else if (GrClip::IsPixelAligned(drawBounds) &&
503 drawBounds.width() > 256 && drawBounds.height() > 256) {
504 // Scissor + clear (round shouldn't do anything since we are pixel aligned)
505 SkIRect scissorRect;
506 drawBounds.round(&scissorRect);
507 this->clear(&scissorRect, *constColor, CanClearFullscreen::kNo);
508 return QuadOptimization::kSubmitted;
509 }
510 }
511
512 // Update overall AA setting.
513 *edgeFlags = newFlags;
514 if (*aa == GrAA::kNo && clipAA == GrAA::kYes &&
515 newFlags != GrQuadAAFlags::kNone) {
516 // The clip was anti-aliased and now the draw needs to be upgraded to AA to
517 // properly reflect the smooth edge of the clip.
518 *aa = GrAA::kYes;
519 }
520 // We intentionally do not downgrade AA here because we don't know if we need to
521 // preserve MSAA (see GrQuadAAFlags docs). But later in the pipeline, the ops can
522 // use GrResolveAATypeForQuad() to turn off coverage AA when all flags are off.
523
524 // deviceQuad is exactly the intersection of original quad and clip, so it can be
525 // drawn with no clip (submitted by caller)
526 return QuadOptimization::kClipApplied;
527 } else {
528 // The quads have been updated to better fit the clip bounds, but can't get rid of
529 // the clip entirely
530 return QuadOptimization::kCropped;
531 }
532 } else if (constColor) {
533 // Rounded corners and constant filled color (limit ourselves to solid colors because
534 // there is no way to use custom local coordinates with drawRRect).
535 if (GrQuadUtils::CropToRect(clipBounds, clipAA, &newFlags, deviceQuad, localQuad) &&
536 deviceQuad->quadType() == GrQuad::Type::kAxisAligned &&
537 deviceQuad->bounds().contains(clipBounds)) {
538 // Since the cropped quad became a rectangle which covered the bounds of the rrect,
539 // we can draw the rrect directly and ignore the edge flags
540 GrPaint paint;
541 clear_to_grpaint(*constColor, &paint);
542 this->drawRRect(GrFixedClip::Disabled(), std::move(paint), clipAA, SkMatrix::I(),
543 clipRRect, GrStyle::SimpleFill());
544 return QuadOptimization::kSubmitted;
545 } else {
546 // The quad has been updated to better fit clip bounds, but can't remove the clip
547 return QuadOptimization::kCropped;
548 }
549 }
550 }
551
552 // Crop the quad to the conservative bounds of the clip.
553 SkIRect clipDevBounds;
554 clip.getConservativeBounds(rtRect.width(), rtRect.height(), &clipDevBounds);
555 SkRect clipBounds = SkRect::Make(clipDevBounds);
556
557 // One final check for discarding, since we may have gone here directly due to a complex clip
558 if (!clipBounds.intersects(drawBounds)) {
559 return QuadOptimization::kDiscarded;
560 }
561
562 // Even if this were to return true, the crop rect does not exactly match the clip, so can not
563 // report explicit-clip. Since these edges aren't visible, don't update the final edge flags.
564 GrQuadUtils::CropToRect(clipBounds, clipAA, &newFlags, deviceQuad, localQuad);
565
566 return QuadOptimization::kCropped;
567 }
568
drawFilledQuad(const GrClip & clip,GrPaint && paint,GrAA aa,GrQuadAAFlags edgeFlags,const GrQuad & deviceQuad,const GrQuad & localQuad,const GrUserStencilSettings * ss)569 void GrRenderTargetContext::drawFilledQuad(const GrClip& clip,
570 GrPaint&& paint,
571 GrAA aa,
572 GrQuadAAFlags edgeFlags,
573 const GrQuad& deviceQuad,
574 const GrQuad& localQuad,
575 const GrUserStencilSettings* ss) {
576 ASSERT_SINGLE_OWNER
577 RETURN_IF_ABANDONED
578 SkDEBUGCODE(this->validate();)
579 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFilledQuad", fContext);
580
581 AutoCheckFlush acf(this->drawingManager());
582
583 SkPMColor4f* constColor = nullptr;
584 SkPMColor4f paintColor;
585 if (!ss && !paint.numCoverageFragmentProcessors() &&
586 paint.isConstantBlendedColor(&paintColor)) {
587 // Only consider clears/rrects when it's easy to guarantee 100% fill with single color
588 constColor = &paintColor;
589 }
590
591 GrQuad croppedDeviceQuad = deviceQuad;
592 GrQuad croppedLocalQuad = localQuad;
593 QuadOptimization opt = this->attemptQuadOptimization(clip, constColor, ss, &aa, &edgeFlags,
594 &croppedDeviceQuad, &croppedLocalQuad);
595 if (opt >= QuadOptimization::kClipApplied) {
596 // These optimizations require caller to add an op themselves
597 const GrClip& finalClip = opt == QuadOptimization::kClipApplied ? GrFixedClip::Disabled()
598 : clip;
599 GrAAType aaType = ss ? (aa == GrAA::kYes ? GrAAType::kMSAA : GrAAType::kNone)
600 : this->chooseAAType(aa);
601 this->addDrawOp(finalClip, GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeFlags,
602 croppedDeviceQuad, croppedLocalQuad, ss));
603 }
604 // All other optimization levels were completely handled inside attempt(), so no extra op needed
605 }
606
drawTexturedQuad(const GrClip & clip,sk_sp<GrTextureProxy> proxy,GrColorType srcColorType,sk_sp<GrColorSpaceXform> textureXform,GrSamplerState::Filter filter,const SkPMColor4f & color,SkBlendMode blendMode,GrAA aa,GrQuadAAFlags edgeFlags,const GrQuad & deviceQuad,const GrQuad & localQuad,const SkRect * domain)607 void GrRenderTargetContext::drawTexturedQuad(const GrClip& clip,
608 sk_sp<GrTextureProxy> proxy,
609 GrColorType srcColorType,
610 sk_sp<GrColorSpaceXform> textureXform,
611 GrSamplerState::Filter filter,
612 const SkPMColor4f& color,
613 SkBlendMode blendMode,
614 GrAA aa,
615 GrQuadAAFlags edgeFlags,
616 const GrQuad& deviceQuad,
617 const GrQuad& localQuad,
618 const SkRect* domain) {
619 ASSERT_SINGLE_OWNER
620 RETURN_IF_ABANDONED
621 SkDEBUGCODE(this->validate();)
622 SkASSERT(proxy);
623 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTexturedQuad", fContext);
624
625 AutoCheckFlush acf(this->drawingManager());
626
627 // Functionally this is very similar to drawFilledQuad except that there's no constColor to
628 // enable the kSubmitted optimizations, no stencil settings support, and its a GrTextureOp.
629 GrQuad croppedDeviceQuad = deviceQuad;
630 GrQuad croppedLocalQuad = localQuad;
631 QuadOptimization opt = this->attemptQuadOptimization(clip, nullptr, nullptr, &aa, &edgeFlags,
632 &croppedDeviceQuad, &croppedLocalQuad);
633
634 SkASSERT(opt != QuadOptimization::kSubmitted);
635 if (opt != QuadOptimization::kDiscarded) {
636 // And the texture op if not discarded
637 const GrClip& finalClip = opt == QuadOptimization::kClipApplied ? GrFixedClip::Disabled()
638 : clip;
639 GrAAType aaType = this->chooseAAType(aa);
640 auto clampType = GrColorTypeClampType(this->colorInfo().colorType());
641 auto saturate = clampType == GrClampType::kManual ? GrTextureOp::Saturate::kYes
642 : GrTextureOp::Saturate::kNo;
643 // Use the provided domain, although hypothetically we could detect that the cropped local
644 // quad is sufficiently inside the domain and the constraint could be dropped.
645 this->addDrawOp(finalClip,
646 GrTextureOp::Make(fContext, std::move(proxy), srcColorType,
647 std::move(textureXform), filter, color, saturate,
648 blendMode, aaType, edgeFlags, croppedDeviceQuad,
649 croppedLocalQuad, domain));
650 }
651 }
652
drawRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect,const GrStyle * style)653 void GrRenderTargetContext::drawRect(const GrClip& clip,
654 GrPaint&& paint,
655 GrAA aa,
656 const SkMatrix& viewMatrix,
657 const SkRect& rect,
658 const GrStyle* style) {
659 if (!style) {
660 style = &GrStyle::SimpleFill();
661 }
662 ASSERT_SINGLE_OWNER
663 RETURN_IF_ABANDONED
664 SkDEBUGCODE(this->validate();)
665 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRect", fContext);
666
667 // Path effects should've been devolved to a path in SkGpuDevice
668 SkASSERT(!style->pathEffect());
669
670 AutoCheckFlush acf(this->drawingManager());
671
672 const SkStrokeRec& stroke = style->strokeRec();
673 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
674 // Fills the rect, using rect as its own local coordinates
675 this->fillRectToRect(clip, std::move(paint), aa, viewMatrix, rect, rect);
676 return;
677 } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
678 stroke.getStyle() == SkStrokeRec::kHairline_Style) {
679 if ((!rect.width() || !rect.height()) &&
680 SkStrokeRec::kHairline_Style != stroke.getStyle()) {
681 SkScalar r = stroke.getWidth() / 2;
682 // TODO: Move these stroke->fill fallbacks to GrShape?
683 switch (stroke.getJoin()) {
684 case SkPaint::kMiter_Join:
685 this->drawRect(
686 clip, std::move(paint), aa, viewMatrix,
687 {rect.fLeft - r, rect.fTop - r, rect.fRight + r, rect.fBottom + r},
688 &GrStyle::SimpleFill());
689 return;
690 case SkPaint::kRound_Join:
691 // Raster draws nothing when both dimensions are empty.
692 if (rect.width() || rect.height()){
693 SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r);
694 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect,
695 GrStyle::SimpleFill());
696 return;
697 }
698 case SkPaint::kBevel_Join:
699 if (!rect.width()) {
700 this->drawRect(clip, std::move(paint), aa, viewMatrix,
701 {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom},
702 &GrStyle::SimpleFill());
703 } else {
704 this->drawRect(clip, std::move(paint), aa, viewMatrix,
705 {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r},
706 &GrStyle::SimpleFill());
707 }
708 return;
709 }
710 }
711
712 std::unique_ptr<GrDrawOp> op;
713
714 GrAAType aaType = this->chooseAAType(aa);
715 op = GrStrokeRectOp::Make(fContext, std::move(paint), aaType, viewMatrix, rect, stroke);
716 // op may be null if the stroke is not supported or if using coverage aa and the view matrix
717 // does not preserve rectangles.
718 if (op) {
719 this->addDrawOp(clip, std::move(op));
720 return;
721 }
722 }
723 assert_alive(paint);
724 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(rect, *style));
725 }
726
drawQuadSet(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const QuadSetEntry quads[],int cnt)727 void GrRenderTargetContext::drawQuadSet(const GrClip& clip, GrPaint&& paint, GrAA aa,
728 const SkMatrix& viewMatrix, const QuadSetEntry quads[],
729 int cnt) {
730 GrAAType aaType = this->chooseAAType(aa);
731 this->addDrawOp(clip, GrFillRectOp::MakeSet(fContext, std::move(paint), aaType, viewMatrix,
732 quads, cnt));
733 }
734
maxWindowRectangles() const735 int GrRenderTargetContextPriv::maxWindowRectangles() const {
736 return fRenderTargetContext->fRenderTargetProxy->maxWindowRectangles(
737 *fRenderTargetContext->caps());
738 }
739
canDiscardPreviousOpsOnFullClear() const740 GrOpsTask::CanDiscardPreviousOps GrRenderTargetContext::canDiscardPreviousOpsOnFullClear(
741 ) const {
742 #if GR_TEST_UTILS
743 if (fPreserveOpsOnFullClear_TestingOnly) {
744 return GrOpsTask::CanDiscardPreviousOps::kNo;
745 }
746 #endif
747 // Regardless of how the clear is implemented (native clear or a fullscreen quad), all prior ops
748 // would normally be overwritten. The one exception is if the render target context is marked as
749 // needing a stencil buffer then there may be a prior op that writes to the stencil buffer.
750 // Although the clear will ignore the stencil buffer, following draw ops may not so we can't get
751 // rid of all the preceding ops. Beware! If we ever add any ops that have a side effect beyond
752 // modifying the stencil buffer we will need a more elaborate tracking system (skbug.com/7002).
753 return GrOpsTask::CanDiscardPreviousOps(!fNumStencilSamples);
754 }
755
setNeedsStencil(bool useMixedSamplesIfNotMSAA)756 void GrRenderTargetContext::setNeedsStencil(bool useMixedSamplesIfNotMSAA) {
757 // Don't clear stencil until after we've changed fNumStencilSamples. This ensures we don't loop
758 // forever in the event that there are driver bugs and we need to clear as a draw.
759 bool hasInitializedStencil = fNumStencilSamples > 0;
760
761 int numRequiredSamples = this->numSamples();
762 if (useMixedSamplesIfNotMSAA && 1 == numRequiredSamples) {
763 SkASSERT(fRenderTargetProxy->canUseMixedSamples(*this->caps()));
764 numRequiredSamples = this->caps()->internalMultisampleCount(
765 this->asSurfaceProxy()->backendFormat());
766 }
767 SkASSERT(numRequiredSamples > 0);
768
769 if (numRequiredSamples > fNumStencilSamples) {
770 fNumStencilSamples = numRequiredSamples;
771 fRenderTargetProxy->setNeedsStencil(fNumStencilSamples);
772 }
773
774 if (!hasInitializedStencil) {
775 if (this->caps()->performStencilClearsAsDraws()) {
776 // There is a driver bug with clearing stencil. We must use an op to manually clear the
777 // stencil buffer before the op that required 'setNeedsStencil'.
778 this->internalStencilClear(GrFixedClip::Disabled(), /* inside mask */ false);
779 } else {
780 this->getOpsTask()->setInitialStencilContent(
781 GrOpsTask::StencilContent::kUserBitsCleared);
782 }
783 }
784 }
785
clearStencilClip(const GrFixedClip & clip,bool insideStencilMask)786 void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
787 ASSERT_SINGLE_OWNER_PRIV
788 RETURN_IF_ABANDONED_PRIV
789 SkDEBUGCODE(fRenderTargetContext->validate();)
790 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clearStencilClip",
791 fRenderTargetContext->fContext);
792
793 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
794
795 fRenderTargetContext->internalStencilClear(clip, insideStencilMask);
796 }
797
internalStencilClear(const GrFixedClip & clip,bool insideStencilMask)798 void GrRenderTargetContext::internalStencilClear(const GrFixedClip& clip, bool insideStencilMask) {
799 this->setNeedsStencil(/* useMixedSamplesIfNotMSAA = */ false);
800
801 if (this->caps()->performStencilClearsAsDraws()) {
802 const GrUserStencilSettings* ss = GrStencilSettings::SetClipBitSettings(insideStencilMask);
803 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
804
805 // Configure the paint to have no impact on the color buffer
806 GrPaint paint;
807 paint.setXPFactory(GrDisableColorXPFactory::Get());
808 this->addDrawOp(clip, GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
809 rtRect, ss));
810 } else {
811 std::unique_ptr<GrOp> op(GrClearStencilClipOp::Make(fContext, clip, insideStencilMask,
812 fRenderTargetProxy.get()));
813 if (!op) {
814 return;
815 }
816 this->addOp(std::move(op));
817 }
818 }
819
stencilPath(const GrHardClip & clip,GrAA doStencilMSAA,const SkMatrix & viewMatrix,sk_sp<const GrPath> path)820 void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
821 GrAA doStencilMSAA,
822 const SkMatrix& viewMatrix,
823 sk_sp<const GrPath> path) {
824 ASSERT_SINGLE_OWNER_PRIV
825 RETURN_IF_ABANDONED_PRIV
826 SkDEBUGCODE(fRenderTargetContext->validate();)
827 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilPath",
828 fRenderTargetContext->fContext);
829
830 // TODO: extract portions of checkDraw that are relevant to path stenciling.
831 SkASSERT(path);
832 SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport());
833
834 // FIXME: Use path bounds instead of this WAR once
835 // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
836 SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height());
837
838 // Setup clip
839 GrAppliedHardClip appliedClip;
840 if (!clip.apply(fRenderTargetContext->width(), fRenderTargetContext->height(), &appliedClip,
841 &bounds)) {
842 return;
843 }
844
845 std::unique_ptr<GrOp> op = GrStencilPathOp::Make(fRenderTargetContext->fContext,
846 viewMatrix,
847 GrAA::kYes == doStencilMSAA,
848 appliedClip.hasStencilClip(),
849 appliedClip.scissorState(),
850 std::move(path));
851 if (!op) {
852 return;
853 }
854 op->setClippedBounds(bounds);
855
856 fRenderTargetContext->setNeedsStencil(GrAA::kYes == doStencilMSAA);
857 fRenderTargetContext->addOp(std::move(op));
858 }
859
drawTextureSet(const GrClip & clip,const TextureSetEntry set[],int cnt,GrSamplerState::Filter filter,SkBlendMode mode,GrAA aa,SkCanvas::SrcRectConstraint constraint,const SkMatrix & viewMatrix,sk_sp<GrColorSpaceXform> texXform)860 void GrRenderTargetContext::drawTextureSet(const GrClip& clip, const TextureSetEntry set[], int cnt,
861 GrSamplerState::Filter filter, SkBlendMode mode,
862 GrAA aa, SkCanvas::SrcRectConstraint constraint,
863 const SkMatrix& viewMatrix,
864 sk_sp<GrColorSpaceXform> texXform) {
865 ASSERT_SINGLE_OWNER
866 RETURN_IF_ABANDONED
867 SkDEBUGCODE(this->validate();)
868 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureSet", fContext);
869
870 if (mode != SkBlendMode::kSrcOver ||
871 !fContext->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
872 // Draw one at a time since the bulk API doesn't support non src-over blending, or the
873 // backend can't support the bulk geometry processor yet.
874 SkMatrix ctm;
875 for (int i = 0; i < cnt; ++i) {
876 float alpha = set[i].fAlpha;
877 ctm = viewMatrix;
878 if (set[i].fPreViewMatrix) {
879 ctm.preConcat(*set[i].fPreViewMatrix);
880 }
881
882 GrQuad quad, srcQuad;
883 if (set[i].fDstClipQuad) {
884 quad = GrQuad::MakeFromSkQuad(set[i].fDstClipQuad, ctm);
885
886 SkPoint srcPts[4];
887 GrMapRectPoints(set[i].fDstRect, set[i].fSrcRect, set[i].fDstClipQuad, srcPts, 4);
888 srcQuad = GrQuad::MakeFromSkQuad(srcPts, SkMatrix::I());
889 } else {
890 quad = GrQuad::MakeFromRect(set[i].fDstRect, ctm);
891 srcQuad = GrQuad(set[i].fSrcRect);
892 }
893
894 const SkRect* domain = constraint == SkCanvas::kStrict_SrcRectConstraint
895 ? &set[i].fSrcRect : nullptr;
896 this->drawTexturedQuad(clip, set[i].fProxy, set[i].fSrcColorType, texXform, filter,
897 {alpha, alpha, alpha, alpha}, mode, aa, set[i].fAAFlags,
898 quad, srcQuad, domain);
899 }
900 } else {
901 // Can use a single op, avoiding GrPaint creation, and can batch across proxies
902 AutoCheckFlush acf(this->drawingManager());
903 GrAAType aaType = this->chooseAAType(aa);
904 auto clampType = GrColorTypeClampType(this->colorInfo().colorType());
905 auto saturate = clampType == GrClampType::kManual ? GrTextureOp::Saturate::kYes
906 : GrTextureOp::Saturate::kNo;
907 auto op = GrTextureOp::MakeSet(fContext, set, cnt, filter, saturate, aaType, constraint,
908 viewMatrix, std::move(texXform));
909 this->addDrawOp(clip, std::move(op));
910 }
911 }
912
drawVertices(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,sk_sp<SkVertices> vertices,const SkVertices::Bone bones[],int boneCount,GrPrimitiveType * overridePrimType)913 void GrRenderTargetContext::drawVertices(const GrClip& clip,
914 GrPaint&& paint,
915 const SkMatrix& viewMatrix,
916 sk_sp<SkVertices> vertices,
917 const SkVertices::Bone bones[],
918 int boneCount,
919 GrPrimitiveType* overridePrimType) {
920 ASSERT_SINGLE_OWNER
921 RETURN_IF_ABANDONED
922 SkDEBUGCODE(this->validate();)
923 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawVertices", fContext);
924
925 AutoCheckFlush acf(this->drawingManager());
926
927 SkASSERT(vertices);
928 GrAAType aaType = this->chooseAAType(GrAA::kNo);
929 std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make(
930 fContext, std::move(paint), std::move(vertices), bones, boneCount, viewMatrix, aaType,
931 this->colorInfo().refColorSpaceXformFromSRGB(), overridePrimType);
932 this->addDrawOp(clip, std::move(op));
933 }
934
935 ///////////////////////////////////////////////////////////////////////////////
936
drawAtlas(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,int spriteCount,const SkRSXform xform[],const SkRect texRect[],const SkColor colors[])937 void GrRenderTargetContext::drawAtlas(const GrClip& clip,
938 GrPaint&& paint,
939 const SkMatrix& viewMatrix,
940 int spriteCount,
941 const SkRSXform xform[],
942 const SkRect texRect[],
943 const SkColor colors[]) {
944 ASSERT_SINGLE_OWNER
945 RETURN_IF_ABANDONED
946 SkDEBUGCODE(this->validate();)
947 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawAtlas", fContext);
948
949 AutoCheckFlush acf(this->drawingManager());
950
951 GrAAType aaType = this->chooseAAType(GrAA::kNo);
952 std::unique_ptr<GrDrawOp> op = GrDrawAtlasOp::Make(fContext, std::move(paint), viewMatrix,
953 aaType, spriteCount, xform, texRect, colors);
954 this->addDrawOp(clip, std::move(op));
955 }
956
957 ///////////////////////////////////////////////////////////////////////////////
958
drawRRect(const GrClip & origClip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & rrect,const GrStyle & style)959 void GrRenderTargetContext::drawRRect(const GrClip& origClip,
960 GrPaint&& paint,
961 GrAA aa,
962 const SkMatrix& viewMatrix,
963 const SkRRect& rrect,
964 const GrStyle& style) {
965 ASSERT_SINGLE_OWNER
966 RETURN_IF_ABANDONED
967 SkDEBUGCODE(this->validate();)
968 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRRect", fContext);
969
970 const SkStrokeRec& stroke = style.strokeRec();
971 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.isEmpty()) {
972 return;
973 }
974
975 GrNoClip noclip;
976 const GrClip* clip = &origClip;
977 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
978 // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
979 // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it
980 // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
981 // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
982 // can be ignored. We'd prefer to fix this in the framework by removing the clips calls. This
983 // only works for filled rrects since the stroke width outsets beyond the rrect itself.
984 SkRRect devRRect;
985 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.transform(viewMatrix, &devRRect) &&
986 clip->quickContains(devRRect)) {
987 clip = &noclip;
988 }
989 #endif
990 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
991
992 AutoCheckFlush acf(this->drawingManager());
993
994 GrAAType aaType = this->chooseAAType(aa);
995
996 std::unique_ptr<GrDrawOp> op;
997 if (GrAAType::kCoverage == aaType && rrect.isSimple() &&
998 rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY &&
999 viewMatrix.rectStaysRect() && viewMatrix.isSimilarity()) {
1000 // In coverage mode, we draw axis-aligned circular roundrects with the GrOvalOpFactory
1001 // to avoid perf regressions on some platforms.
1002 assert_alive(paint);
1003 op = GrOvalOpFactory::MakeCircularRRectOp(
1004 fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
1005 }
1006 if (!op && style.isSimpleFill()) {
1007 assert_alive(paint);
1008 op = GrFillRRectOp::Make(
1009 fContext, aaType, viewMatrix, rrect, *this->caps(), std::move(paint));
1010 }
1011 if (!op && GrAAType::kCoverage == aaType) {
1012 assert_alive(paint);
1013 op = GrOvalOpFactory::MakeRRectOp(
1014 fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
1015 }
1016 if (op) {
1017 this->addDrawOp(*clip, std::move(op));
1018 return;
1019 }
1020
1021 assert_alive(paint);
1022 this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix,
1023 GrShape(rrect, style));
1024 }
1025
1026 ///////////////////////////////////////////////////////////////////////////////
1027
map(const SkMatrix & m,const SkPoint3 & pt)1028 static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
1029 SkPoint3 result;
1030 m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
1031 result.fZ = pt.fZ;
1032 return result;
1033 }
1034
drawFastShadow(const GrClip & clip,const SkMatrix & viewMatrix,const SkPath & path,const SkDrawShadowRec & rec)1035 bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
1036 const SkMatrix& viewMatrix,
1037 const SkPath& path,
1038 const SkDrawShadowRec& rec) {
1039 ASSERT_SINGLE_OWNER
1040 if (fContext->priv().abandoned()) {
1041 return true;
1042 }
1043 SkDEBUGCODE(this->validate();)
1044 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFastShadow", fContext);
1045
1046 // check z plane
1047 bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
1048 !SkScalarNearlyZero(rec.fZPlaneParams.fY));
1049 bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1050 if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
1051 return false;
1052 }
1053
1054 SkRRect rrect;
1055 SkRect rect;
1056 // we can only handle rects, circles, and rrects with circular corners
1057 bool isRRect = path.isRRect(&rrect) && SkRRectPriv::IsSimpleCircular(rrect) &&
1058 rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero;
1059 if (!isRRect &&
1060 path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
1061 rect.width() > SK_ScalarNearlyZero) {
1062 rrect.setOval(rect);
1063 isRRect = true;
1064 }
1065 if (!isRRect && path.isRect(&rect)) {
1066 rrect.setRect(rect);
1067 isRRect = true;
1068 }
1069
1070 if (!isRRect) {
1071 return false;
1072 }
1073
1074 if (rrect.isEmpty()) {
1075 return true;
1076 }
1077
1078 AutoCheckFlush acf(this->drawingManager());
1079
1080 // transform light
1081 SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
1082
1083 // 1/scale
1084 SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1085 SkScalarInvert(SkScalarAbs(viewMatrix[SkMatrix::kMScaleX])) :
1086 sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1087 viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1088
1089 SkScalar occluderHeight = rec.fZPlaneParams.fZ;
1090 bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1091
1092 if (SkColorGetA(rec.fAmbientColor) > 0) {
1093 SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
1094 const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
1095 const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
1096
1097 // Outset the shadow rrect to the border of the penumbra
1098 SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1099 SkRRect ambientRRect;
1100 SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1101 // If the rrect was an oval then its outset will also be one.
1102 // We set it explicitly to avoid errors.
1103 if (rrect.isOval()) {
1104 ambientRRect = SkRRect::MakeOval(outsetRect);
1105 } else {
1106 SkScalar outsetRad = SkRRectPriv::GetSimpleRadii(rrect).fX + ambientPathOutset;
1107 ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1108 }
1109
1110 GrColor ambientColor = SkColorToPremulGrColor(rec.fAmbientColor);
1111 if (transparent) {
1112 // set a large inset to force a fill
1113 devSpaceInsetWidth = ambientRRect.width();
1114 }
1115
1116 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1117 ambientColor,
1118 viewMatrix,
1119 ambientRRect,
1120 devSpaceAmbientBlur,
1121 devSpaceInsetWidth);
1122 if (op) {
1123 this->addDrawOp(clip, std::move(op));
1124 }
1125 }
1126
1127 if (SkColorGetA(rec.fSpotColor) > 0) {
1128 SkScalar devSpaceSpotBlur;
1129 SkScalar spotScale;
1130 SkVector spotOffset;
1131 SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY,
1132 devLightPos.fZ, rec.fLightRadius,
1133 &devSpaceSpotBlur, &spotScale, &spotOffset);
1134 // handle scale of radius due to CTM
1135 const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1136
1137 // Adjust translate for the effect of the scale.
1138 spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1139 spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1140 // This offset is in dev space, need to transform it into source space.
1141 SkMatrix ctmInverse;
1142 if (viewMatrix.invert(&ctmInverse)) {
1143 ctmInverse.mapPoints(&spotOffset, 1);
1144 } else {
1145 // Since the matrix is a similarity, this should never happen, but just in case...
1146 SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1147 SkASSERT(false);
1148 }
1149
1150 // Compute the transformed shadow rrect
1151 SkRRect spotShadowRRect;
1152 SkMatrix shadowTransform;
1153 shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1154 rrect.transform(shadowTransform, &spotShadowRRect);
1155 SkScalar spotRadius = SkRRectPriv::GetSimpleRadii(spotShadowRRect).fX;
1156
1157 // Compute the insetWidth
1158 SkScalar blurOutset = srcSpaceSpotBlur;
1159 SkScalar insetWidth = blurOutset;
1160 if (transparent) {
1161 // If transparent, just do a fill
1162 insetWidth += spotShadowRRect.width();
1163 } else {
1164 // For shadows, instead of using a stroke we specify an inset from the penumbra
1165 // border. We want to extend this inset area so that it meets up with the caster
1166 // geometry. The inset geometry will by default already be inset by the blur width.
1167 //
1168 // We compare the min and max corners inset by the radius between the original
1169 // rrect and the shadow rrect. The distance between the two plus the difference
1170 // between the scaled radius and the original radius gives the distance from the
1171 // transformed shadow shape to the original shape in that corner. The max
1172 // of these gives the maximum distance we need to cover.
1173 //
1174 // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1175 // that to get the full insetWidth.
1176 SkScalar maxOffset;
1177 if (rrect.isRect()) {
1178 // Manhattan distance works better for rects
1179 maxOffset = SkTMax(SkTMax(SkTAbs(spotShadowRRect.rect().fLeft -
1180 rrect.rect().fLeft),
1181 SkTAbs(spotShadowRRect.rect().fTop -
1182 rrect.rect().fTop)),
1183 SkTMax(SkTAbs(spotShadowRRect.rect().fRight -
1184 rrect.rect().fRight),
1185 SkTAbs(spotShadowRRect.rect().fBottom -
1186 rrect.rect().fBottom)));
1187 } else {
1188 SkScalar dr = spotRadius - SkRRectPriv::GetSimpleRadii(rrect).fX;
1189 SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1190 rrect.rect().fLeft + dr,
1191 spotShadowRRect.rect().fTop -
1192 rrect.rect().fTop + dr);
1193 SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1194 rrect.rect().fRight - dr,
1195 spotShadowRRect.rect().fBottom -
1196 rrect.rect().fBottom - dr);
1197 maxOffset = SkScalarSqrt(SkTMax(SkPointPriv::LengthSqd(upperLeftOffset),
1198 SkPointPriv::LengthSqd(lowerRightOffset))) + dr;
1199 }
1200 insetWidth += SkTMax(blurOutset, maxOffset);
1201 }
1202
1203 // Outset the shadow rrect to the border of the penumbra
1204 SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1205 if (spotShadowRRect.isOval()) {
1206 spotShadowRRect = SkRRect::MakeOval(outsetRect);
1207 } else {
1208 SkScalar outsetRad = spotRadius + blurOutset;
1209 spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1210 }
1211
1212 GrColor spotColor = SkColorToPremulGrColor(rec.fSpotColor);
1213
1214 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1215 spotColor,
1216 viewMatrix,
1217 spotShadowRRect,
1218 2.0f * devSpaceSpotBlur,
1219 insetWidth);
1220 if (op) {
1221 this->addDrawOp(clip, std::move(op));
1222 }
1223 }
1224
1225 return true;
1226 }
1227
1228 ///////////////////////////////////////////////////////////////////////////////
1229
drawFilledDRRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & origOuter,const SkRRect & origInner)1230 bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
1231 GrPaint&& paint,
1232 GrAA aa,
1233 const SkMatrix& viewMatrix,
1234 const SkRRect& origOuter,
1235 const SkRRect& origInner) {
1236 SkASSERT(!origInner.isEmpty());
1237 SkASSERT(!origOuter.isEmpty());
1238
1239 SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
1240
1241 GrAAType aaType = this->chooseAAType(aa);
1242
1243 if (GrAAType::kMSAA == aaType) {
1244 return false;
1245 }
1246
1247 if (GrAAType::kCoverage == aaType && SkRRectPriv::IsCircle(*inner)
1248 && SkRRectPriv::IsCircle(*outer)) {
1249 auto outerR = outer->width() / 2.f;
1250 auto innerR = inner->width() / 2.f;
1251 auto cx = outer->getBounds().fLeft + outerR;
1252 auto cy = outer->getBounds().fTop + outerR;
1253 if (SkScalarNearlyEqual(cx, inner->getBounds().fLeft + innerR) &&
1254 SkScalarNearlyEqual(cy, inner->getBounds().fTop + innerR)) {
1255 auto avgR = (innerR + outerR) / 2.f;
1256 auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR);
1257 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
1258 stroke.setStrokeStyle(outerR - innerR);
1259 auto op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix,
1260 circleBounds, GrStyle(stroke, nullptr),
1261 this->caps()->shaderCaps());
1262 if (op) {
1263 this->addDrawOp(clip, std::move(op));
1264 return true;
1265 }
1266 assert_alive(paint);
1267 }
1268 }
1269
1270 GrClipEdgeType innerEdgeType, outerEdgeType;
1271 if (GrAAType::kCoverage == aaType) {
1272 innerEdgeType = GrClipEdgeType::kInverseFillAA;
1273 outerEdgeType = GrClipEdgeType::kFillAA;
1274 } else {
1275 innerEdgeType = GrClipEdgeType::kInverseFillBW;
1276 outerEdgeType = GrClipEdgeType::kFillBW;
1277 }
1278
1279 SkMatrix inverseVM;
1280 if (!viewMatrix.isIdentity()) {
1281 if (!origInner.transform(viewMatrix, inner.writable())) {
1282 return false;
1283 }
1284 if (!origOuter.transform(viewMatrix, outer.writable())) {
1285 return false;
1286 }
1287 if (!viewMatrix.invert(&inverseVM)) {
1288 return false;
1289 }
1290 } else {
1291 inverseVM.reset();
1292 }
1293
1294 const auto& caps = *this->caps()->shaderCaps();
1295 // TODO these need to be a geometry processors
1296 auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps);
1297 if (!innerEffect) {
1298 return false;
1299 }
1300
1301 auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps);
1302 if (!outerEffect) {
1303 return false;
1304 }
1305
1306 paint.addCoverageFragmentProcessor(std::move(innerEffect));
1307 paint.addCoverageFragmentProcessor(std::move(outerEffect));
1308
1309 SkRect bounds = outer->getBounds();
1310 if (GrAAType::kCoverage == aaType) {
1311 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1312 }
1313
1314 this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds,
1315 inverseVM);
1316 return true;
1317 }
1318
drawDRRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & outer,const SkRRect & inner)1319 void GrRenderTargetContext::drawDRRect(const GrClip& clip,
1320 GrPaint&& paint,
1321 GrAA aa,
1322 const SkMatrix& viewMatrix,
1323 const SkRRect& outer,
1324 const SkRRect& inner) {
1325 ASSERT_SINGLE_OWNER
1326 RETURN_IF_ABANDONED
1327 SkDEBUGCODE(this->validate();)
1328 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawDRRect", fContext);
1329
1330 SkASSERT(!outer.isEmpty());
1331 SkASSERT(!inner.isEmpty());
1332
1333 AutoCheckFlush acf(this->drawingManager());
1334
1335 if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) {
1336 return;
1337 }
1338 assert_alive(paint);
1339
1340 SkPath path;
1341 path.setIsVolatile(true);
1342 path.addRRect(inner);
1343 path.addRRect(outer);
1344 path.setFillType(SkPath::kEvenOdd_FillType);
1345 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path));
1346 }
1347
1348 ///////////////////////////////////////////////////////////////////////////////
1349
drawRegion(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRegion & region,const GrStyle & style,const GrUserStencilSettings * ss)1350 void GrRenderTargetContext::drawRegion(const GrClip& clip,
1351 GrPaint&& paint,
1352 GrAA aa,
1353 const SkMatrix& viewMatrix,
1354 const SkRegion& region,
1355 const GrStyle& style,
1356 const GrUserStencilSettings* ss) {
1357 ASSERT_SINGLE_OWNER
1358 RETURN_IF_ABANDONED
1359 SkDEBUGCODE(this->validate();)
1360 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRegion", fContext);
1361
1362 if (GrAA::kYes == aa) {
1363 // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
1364 // to see whether aa is really required.
1365 if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
1366 SkScalarIsInt(viewMatrix.getTranslateX()) &&
1367 SkScalarIsInt(viewMatrix.getTranslateY())) {
1368 aa = GrAA::kNo;
1369 }
1370 }
1371 bool complexStyle = !style.isSimpleFill();
1372 if (complexStyle || GrAA::kYes == aa) {
1373 SkPath path;
1374 region.getBoundaryPath(&path);
1375 path.setIsVolatile(true);
1376
1377 return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1378 }
1379
1380 GrAAType aaType = this->chooseAAType(GrAA::kNo);
1381 std::unique_ptr<GrDrawOp> op = GrRegionOp::Make(fContext, std::move(paint), viewMatrix, region,
1382 aaType, ss);
1383 this->addDrawOp(clip, std::move(op));
1384 }
1385
drawOval(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & oval,const GrStyle & style)1386 void GrRenderTargetContext::drawOval(const GrClip& clip,
1387 GrPaint&& paint,
1388 GrAA aa,
1389 const SkMatrix& viewMatrix,
1390 const SkRect& oval,
1391 const GrStyle& style) {
1392 ASSERT_SINGLE_OWNER
1393 RETURN_IF_ABANDONED
1394 SkDEBUGCODE(this->validate();)
1395 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawOval", fContext);
1396
1397 const SkStrokeRec& stroke = style.strokeRec();
1398
1399 if (oval.isEmpty() && !style.pathEffect()) {
1400 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1401 return;
1402 }
1403
1404 this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
1405 return;
1406 }
1407
1408 AutoCheckFlush acf(this->drawingManager());
1409
1410 GrAAType aaType = this->chooseAAType(aa);
1411
1412 std::unique_ptr<GrDrawOp> op;
1413 if (GrAAType::kCoverage == aaType && oval.width() > SK_ScalarNearlyZero &&
1414 oval.width() == oval.height() && viewMatrix.isSimilarity()) {
1415 // We don't draw true circles as round rects in coverage mode, because it can
1416 // cause perf regressions on some platforms as compared to the dedicated circle Op.
1417 assert_alive(paint);
1418 op = GrOvalOpFactory::MakeCircleOp(fContext, std::move(paint), viewMatrix, oval, style,
1419 this->caps()->shaderCaps());
1420 }
1421 if (!op && style.isSimpleFill()) {
1422 // GrFillRRectOp has special geometry and a fragment-shader branch to conditionally evaluate
1423 // the arc equation. This same special geometry and fragment branch also turn out to be a
1424 // substantial optimization for drawing ovals (namely, by not evaluating the arc equation
1425 // inside the oval's inner diamond). Given these optimizations, it's a clear win to draw
1426 // ovals the exact same way we do round rects.
1427 assert_alive(paint);
1428 op = GrFillRRectOp::Make(fContext, aaType, viewMatrix, SkRRect::MakeOval(oval),
1429 *this->caps(), std::move(paint));
1430 }
1431 if (!op && GrAAType::kCoverage == aaType) {
1432 assert_alive(paint);
1433 op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1434 this->caps()->shaderCaps());
1435 }
1436 if (op) {
1437 this->addDrawOp(clip, std::move(op));
1438 return;
1439 }
1440
1441 assert_alive(paint);
1442 this->drawShapeUsingPathRenderer(
1443 clip, std::move(paint), aa, viewMatrix,
1444 GrShape(SkRRect::MakeOval(oval), SkPath::kCW_Direction, 2, false, style));
1445 }
1446
drawArc(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const GrStyle & style)1447 void GrRenderTargetContext::drawArc(const GrClip& clip,
1448 GrPaint&& paint,
1449 GrAA aa,
1450 const SkMatrix& viewMatrix,
1451 const SkRect& oval,
1452 SkScalar startAngle,
1453 SkScalar sweepAngle,
1454 bool useCenter,
1455 const GrStyle& style) {
1456 ASSERT_SINGLE_OWNER
1457 RETURN_IF_ABANDONED
1458 SkDEBUGCODE(this->validate();)
1459 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawArc", fContext);
1460
1461 AutoCheckFlush acf(this->drawingManager());
1462
1463 GrAAType aaType = this->chooseAAType(aa);
1464 if (GrAAType::kCoverage == aaType) {
1465 const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
1466 std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(fContext,
1467 std::move(paint),
1468 viewMatrix,
1469 oval,
1470 startAngle,
1471 sweepAngle,
1472 useCenter,
1473 style,
1474 shaderCaps);
1475 if (op) {
1476 this->addDrawOp(clip, std::move(op));
1477 return;
1478 }
1479 assert_alive(paint);
1480 }
1481 this->drawShapeUsingPathRenderer(
1482 clip, std::move(paint), aa, viewMatrix,
1483 GrShape::MakeArc(oval, startAngle, sweepAngle, useCenter, style));
1484 }
1485
drawImageLattice(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,sk_sp<GrTextureProxy> image,GrColorType srcColorType,sk_sp<GrColorSpaceXform> csxf,GrSamplerState::Filter filter,std::unique_ptr<SkLatticeIter> iter,const SkRect & dst)1486 void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
1487 GrPaint&& paint,
1488 const SkMatrix& viewMatrix,
1489 sk_sp<GrTextureProxy> image,
1490 GrColorType srcColorType,
1491 sk_sp<GrColorSpaceXform> csxf,
1492 GrSamplerState::Filter filter,
1493 std::unique_ptr<SkLatticeIter> iter,
1494 const SkRect& dst) {
1495 ASSERT_SINGLE_OWNER
1496 RETURN_IF_ABANDONED
1497 SkDEBUGCODE(this->validate();)
1498 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawImageLattice", fContext);
1499
1500 AutoCheckFlush acf(this->drawingManager());
1501
1502 std::unique_ptr<GrDrawOp> op =
1503 GrLatticeOp::MakeNonAA(fContext, std::move(paint), viewMatrix, std::move(image),
1504 srcColorType, std::move(csxf), filter, std::move(iter), dst);
1505 this->addDrawOp(clip, std::move(op));
1506 }
1507
drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,const SkRect & bounds)1508 void GrRenderTargetContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
1509 const SkRect& bounds) {
1510 std::unique_ptr<GrOp> op(GrDrawableOp::Make(fContext, std::move(drawable), bounds));
1511 SkASSERT(op);
1512 this->addOp(std::move(op));
1513 }
1514
asyncRescaleAndReadPixels(const SkImageInfo & info,const SkIRect & srcRect,SkSurface::RescaleGamma rescaleGamma,SkFilterQuality rescaleQuality,ReadPixelsCallback callback,ReadPixelsContext context)1515 void GrRenderTargetContext::asyncRescaleAndReadPixels(
1516 const SkImageInfo& info, const SkIRect& srcRect, SkSurface::RescaleGamma rescaleGamma,
1517 SkFilterQuality rescaleQuality, ReadPixelsCallback callback, ReadPixelsContext context) {
1518 auto direct = fContext->priv().asDirectContext();
1519 if (!direct) {
1520 callback(context, nullptr);
1521 return;
1522 }
1523 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
1524 callback(context, nullptr);
1525 return;
1526 }
1527 auto dstCT = SkColorTypeToGrColorType(info.colorType());
1528 // TODO: Support reading to gray.
1529 if (dstCT == GrColorType::kUnknown ||
1530 GrColorTypeComponentFlags(dstCT) & kGray_SkColorTypeComponentFlag) {
1531 callback(context, nullptr);
1532 return;
1533 }
1534 bool needsRescale = srcRect.width() != info.width() || srcRect.height() != info.height();
1535 auto colorTypeOfFinalContext = this->colorInfo().colorType();
1536 auto backendFormatOfFinalContext = fRenderTargetProxy->backendFormat();
1537 if (needsRescale) {
1538 colorTypeOfFinalContext = dstCT;
1539 backendFormatOfFinalContext = this->caps()->getDefaultBackendFormat(dstCT,
1540 GrRenderable::kYes);
1541 }
1542 auto readInfo = this->caps()->supportedReadPixelsColorType(colorTypeOfFinalContext,
1543 backendFormatOfFinalContext, dstCT);
1544 // Fail if we can't read from the source surface's color type.
1545 if (readInfo.fColorType == GrColorType::kUnknown) {
1546 callback(context, nullptr);
1547 return;
1548 }
1549 // Fail if read color type does not have all of dstCT's color channels and those missing color
1550 // channels are in the src.
1551 uint32_t dstComponents = GrColorTypeComponentFlags(dstCT);
1552 uint32_t legalReadComponents = GrColorTypeComponentFlags(readInfo.fColorType);
1553 uint32_t srcComponents = GrColorTypeComponentFlags(this->colorInfo().colorType());
1554 if ((~legalReadComponents & dstComponents) & srcComponents) {
1555 callback(context, nullptr);
1556 return;
1557 }
1558
1559 std::unique_ptr<GrRenderTargetContext> tempRTC;
1560 int x = srcRect.fLeft;
1561 int y = srcRect.fTop;
1562 if (needsRescale) {
1563 tempRTC = this->rescale(info, srcRect, rescaleGamma, rescaleQuality);
1564 if (!tempRTC) {
1565 callback(context, nullptr);
1566 return;
1567 }
1568 SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
1569 SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
1570 x = y = 0;
1571 } else {
1572 sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(this->colorInfo().colorSpace(),
1573 this->colorInfo().alphaType(),
1574 info.colorSpace(),
1575 info.alphaType());
1576 // Insert a draw to a temporary surface if we need to do a y-flip or color space conversion.
1577 if (this->origin() == kBottomLeft_GrSurfaceOrigin || xform) {
1578 // We flip or color convert by drawing and we don't currently support drawing to
1579 // kPremul.
1580 if (info.alphaType() == kUnpremul_SkAlphaType) {
1581 callback(context, nullptr);
1582 return;
1583 }
1584 sk_sp<GrTextureProxy> texProxy = sk_ref_sp(fRenderTargetProxy->asTextureProxy());
1585 SkRect srcRectToDraw = SkRect::Make(srcRect);
1586 // If the src is not texturable first try to make a copy to a texture.
1587 if (!texProxy) {
1588 texProxy = GrSurfaceProxy::Copy(fContext, fRenderTargetProxy.get(),
1589 this->colorInfo().colorType(),
1590 GrMipMapped::kNo, srcRect, SkBackingFit::kApprox,
1591 SkBudgeted::kNo);
1592 if (!texProxy) {
1593 callback(context, nullptr);
1594 return;
1595 }
1596 srcRectToDraw = SkRect::MakeWH(srcRect.width(), srcRect.height());
1597 }
1598 tempRTC = direct->priv().makeDeferredRenderTargetContext(
1599 SkBackingFit::kApprox, srcRect.width(), srcRect.height(),
1600 this->colorInfo().colorType(), info.refColorSpace(), 1, GrMipMapped::kNo,
1601 kTopLeft_GrSurfaceOrigin);
1602 if (!tempRTC) {
1603 callback(context, nullptr);
1604 return;
1605 }
1606 tempRTC->drawTexture(GrNoClip(), std::move(texProxy), this->colorInfo().colorType(),
1607 GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
1608 SK_PMColor4fWHITE, srcRectToDraw,
1609 SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo,
1610 GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
1611 SkMatrix::I(), std::move(xform));
1612 x = y = 0;
1613 }
1614 }
1615 auto rtc = tempRTC ? tempRTC.get() : this;
1616 return rtc->asyncReadPixels(SkIRect::MakeXYWH(x, y, info.width(), info.height()),
1617 info.colorType(), callback, context);
1618 }
1619
1620 class GrRenderTargetContext::AsyncReadResult : public SkSurface::AsyncReadResult {
1621 public:
AsyncReadResult(uint32_t inboxID)1622 AsyncReadResult(uint32_t inboxID) : fInboxID(inboxID) {}
~AsyncReadResult()1623 ~AsyncReadResult() override {
1624 for (int i = 0; i < fPlanes.count(); ++i) {
1625 if (!fPlanes[i].fMappedBuffer) {
1626 delete[] static_cast<const char*>(fPlanes[i].fData);
1627 } else {
1628 GrClientMappedBufferManager::BufferFinishedMessageBus::Post(
1629 {std::move(fPlanes[i].fMappedBuffer), fInboxID});
1630 }
1631 }
1632 }
1633
count() const1634 int count() const override { return fPlanes.count(); }
data(int i) const1635 const void* data(int i) const override { return fPlanes[i].fData; }
rowBytes(int i) const1636 size_t rowBytes(int i) const override { return fPlanes[i].fRowBytes; }
1637
addTransferResult(const PixelTransferResult & result,SkISize size,size_t rowBytes,GrClientMappedBufferManager * manager)1638 bool addTransferResult(const PixelTransferResult& result,
1639 SkISize size,
1640 size_t rowBytes,
1641 GrClientMappedBufferManager* manager) {
1642 SkASSERT(!result.fTransferBuffer->isMapped());
1643 const void* mappedData = result.fTransferBuffer->map();
1644 if (!mappedData) {
1645 return false;
1646 }
1647 if (result.fPixelConverter) {
1648 std::unique_ptr<char[]> convertedData(new char[rowBytes * size.height()]);
1649 result.fPixelConverter(convertedData.get(), mappedData);
1650 this->addCpuPlane(std::move(convertedData), rowBytes);
1651 result.fTransferBuffer->unmap();
1652 } else {
1653 manager->insert(result.fTransferBuffer);
1654 this->addMappedPlane(mappedData, rowBytes, std::move(result.fTransferBuffer));
1655 }
1656 return true;
1657 }
1658
addCpuPlane(std::unique_ptr<const char[]> data,size_t rowBytes)1659 void addCpuPlane(std::unique_ptr<const char[]> data, size_t rowBytes) {
1660 SkASSERT(data);
1661 SkASSERT(rowBytes > 0);
1662 fPlanes.emplace_back(data.release(), rowBytes, nullptr);
1663 }
1664
1665 private:
addMappedPlane(const void * data,size_t rowBytes,sk_sp<GrGpuBuffer> mappedBuffer)1666 void addMappedPlane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> mappedBuffer) {
1667 SkASSERT(data);
1668 SkASSERT(rowBytes > 0);
1669 SkASSERT(mappedBuffer);
1670 SkASSERT(mappedBuffer->isMapped());
1671 fPlanes.emplace_back(data, rowBytes, std::move(mappedBuffer));
1672 }
1673
1674 struct Plane {
PlaneGrRenderTargetContext::AsyncReadResult::Plane1675 Plane(const void* data, size_t rowBytes, sk_sp<GrGpuBuffer> buffer)
1676 : fData(data), fRowBytes(rowBytes), fMappedBuffer(std::move(buffer)) {}
1677 const void* fData;
1678 size_t fRowBytes;
1679 // If this is null then fData is heap alloc and must be delete[]ed as const char[].
1680 sk_sp<GrGpuBuffer> fMappedBuffer;
1681 };
1682 SkSTArray<3, Plane> fPlanes;
1683 uint32_t fInboxID;
1684 };
1685
asyncReadPixels(const SkIRect & rect,SkColorType colorType,ReadPixelsCallback callback,ReadPixelsContext context)1686 void GrRenderTargetContext::asyncReadPixels(const SkIRect& rect, SkColorType colorType,
1687 ReadPixelsCallback callback,
1688 ReadPixelsContext context) {
1689 SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
1690 SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
1691
1692 auto directContext = fContext->priv().asDirectContext();
1693 SkASSERT(directContext);
1694 auto mappedBufferManager = directContext->priv().clientMappedBufferManager();
1695
1696 auto transferResult = this->transferPixels(SkColorTypeToGrColorType(colorType), rect);
1697
1698 if (!transferResult.fTransferBuffer) {
1699 auto ii = SkImageInfo::Make(rect.size(), colorType,
1700 this->colorInfo().alphaType(),
1701 this->colorInfo().refColorSpace());
1702 auto result = skstd::make_unique<AsyncReadResult>(0);
1703 std::unique_ptr<char[]> data(new char[ii.computeMinByteSize()]);
1704 SkPixmap pm(ii, data.get(), ii.minRowBytes());
1705 result->addCpuPlane(std::move(data), pm.rowBytes());
1706
1707 if (!this->readPixels(ii, pm.writable_addr(), pm.rowBytes(), {rect.fLeft, rect.fTop})) {
1708 callback(context, nullptr);
1709 }
1710 callback(context, std::move(result));
1711 return;
1712 }
1713
1714 struct FinishContext {
1715 ReadPixelsCallback* fClientCallback;
1716 ReadPixelsContext fClientContext;
1717 SkISize fSize;
1718 SkColorType fColorType;
1719 GrClientMappedBufferManager* fMappedBufferManager;
1720 PixelTransferResult fTransferResult;
1721 };
1722 // Assumption is that the caller would like to flush. We could take a parameter or require an
1723 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
1724 // callback to GrGpu until after the next flush that flushes our op list, though.
1725 auto* finishContext = new FinishContext{callback,
1726 context,
1727 rect.size(),
1728 colorType,
1729 mappedBufferManager,
1730 std::move(transferResult)};
1731 auto finishCallback = [](GrGpuFinishedContext c) {
1732 const auto* context = reinterpret_cast<const FinishContext*>(c);
1733 auto result = skstd::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
1734 size_t rowBytes = context->fSize.width() * SkColorTypeBytesPerPixel(context->fColorType);
1735 if (!result->addTransferResult(context->fTransferResult, context->fSize, rowBytes,
1736 context->fMappedBufferManager)) {
1737 result.reset();
1738 }
1739 (*context->fClientCallback)(context->fClientContext, std::move(result));
1740 delete context;
1741 };
1742 GrFlushInfo flushInfo;
1743 flushInfo.fFinishedContext = finishContext;
1744 flushInfo.fFinishedProc = finishCallback;
1745 this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
1746 }
1747
asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,sk_sp<SkColorSpace> dstColorSpace,const SkIRect & srcRect,const SkISize & dstSize,RescaleGamma rescaleGamma,SkFilterQuality rescaleQuality,ReadPixelsCallback callback,ReadPixelsContext context)1748 void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
1749 sk_sp<SkColorSpace> dstColorSpace,
1750 const SkIRect& srcRect,
1751 const SkISize& dstSize,
1752 RescaleGamma rescaleGamma,
1753 SkFilterQuality rescaleQuality,
1754 ReadPixelsCallback callback,
1755 ReadPixelsContext context) {
1756 SkASSERT(srcRect.fLeft >= 0 && srcRect.fRight <= this->width());
1757 SkASSERT(srcRect.fTop >= 0 && srcRect.fBottom <= this->height());
1758 SkASSERT(!dstSize.isZero());
1759 SkASSERT((dstSize.width() % 2 == 0) && (dstSize.height() % 2 == 0));
1760
1761 auto direct = fContext->priv().asDirectContext();
1762 if (!direct) {
1763 callback(context, nullptr);
1764 return;
1765 }
1766 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
1767 callback(context, nullptr);
1768 return;
1769 }
1770 int x = srcRect.fLeft;
1771 int y = srcRect.fTop;
1772 std::unique_ptr<GrRenderTargetContext> tempRTC;
1773 bool needsRescale = srcRect.size() != dstSize;
1774 if (needsRescale) {
1775 // We assume the caller wants kPremul. There is no way to indicate a preference.
1776 auto info = SkImageInfo::Make(dstSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
1777 dstColorSpace);
1778 // TODO: Incorporate the YUV conversion into last pass of rescaling.
1779 tempRTC = this->rescale(info, srcRect, rescaleGamma, rescaleQuality);
1780 if (!tempRTC) {
1781 callback(context, nullptr);
1782 return;
1783 }
1784 SkASSERT(SkColorSpace::Equals(tempRTC->colorInfo().colorSpace(), info.colorSpace()));
1785 SkASSERT(tempRTC->origin() == kTopLeft_GrSurfaceOrigin);
1786 x = y = 0;
1787 } else {
1788 // We assume the caller wants kPremul. There is no way to indicate a preference.
1789 sk_sp<GrColorSpaceXform> xform = GrColorSpaceXform::Make(
1790 this->colorInfo().colorSpace(), this->colorInfo().alphaType(), dstColorSpace.get(),
1791 kPremul_SkAlphaType);
1792 if (xform) {
1793 sk_sp<GrTextureProxy> texProxy = this->asTextureProxyRef();
1794 // TODO: Do something if the input is not a texture already.
1795 if (!texProxy) {
1796 callback(context, nullptr);
1797 return;
1798 }
1799 SkRect srcRectToDraw = SkRect::Make(srcRect);
1800 tempRTC = direct->priv().makeDeferredRenderTargetContext(
1801 SkBackingFit::kApprox, dstSize.width(), dstSize.height(),
1802 this->colorInfo().colorType(), dstColorSpace, 1, GrMipMapped::kNo,
1803 kTopLeft_GrSurfaceOrigin);
1804 if (!tempRTC) {
1805 callback(context, nullptr);
1806 return;
1807 }
1808 tempRTC->drawTexture(GrNoClip(), std::move(texProxy), this->colorInfo().colorType(),
1809 GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
1810 SK_PMColor4fWHITE, srcRectToDraw,
1811 SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo,
1812 GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
1813 SkMatrix::I(), std::move(xform));
1814 x = y = 0;
1815 }
1816 }
1817 auto srcProxy = tempRTC ? tempRTC->asTextureProxyRef() : this->asTextureProxyRef();
1818 // TODO: Do something if the input is not a texture already.
1819 if (!srcProxy) {
1820 callback(context, nullptr);
1821 return;
1822 }
1823 GrColorType srcColorType = tempRTC ? tempRTC->colorInfo().colorType()
1824 : this->colorInfo().colorType();
1825
1826 auto yRTC = direct->priv().makeDeferredRenderTargetContextWithFallback(
1827 SkBackingFit::kApprox, dstSize.width(), dstSize.height(), GrColorType::kAlpha_8,
1828 dstColorSpace, 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
1829 int halfW = dstSize.width()/2;
1830 int halfH = dstSize.height()/2;
1831 auto uRTC = direct->priv().makeDeferredRenderTargetContextWithFallback(
1832 SkBackingFit::kApprox, halfW, halfH, GrColorType::kAlpha_8, dstColorSpace, 1,
1833 GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
1834 auto vRTC = direct->priv().makeDeferredRenderTargetContextWithFallback(
1835 SkBackingFit::kApprox, halfW, halfH, GrColorType::kAlpha_8, dstColorSpace, 1,
1836 GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
1837 if (!yRTC || !uRTC || !vRTC) {
1838 callback(context, nullptr);
1839 return;
1840 }
1841
1842 static constexpr float kRec601M[] {
1843 65.481f / 255, 128.553f / 255, 24.966f / 255, 16.f / 255, // y
1844 -37.797f / 255, -74.203f / 255, 112.0f / 255, 128.f / 255, // u
1845 112.f / 255, -93.786f / 255, -18.214f / 255, 128.f / 255, // v
1846 };
1847 static constexpr float kRec709M[] {
1848 45.5594f / 255, 156.6288f / 255, 15.8118f / 255, 16.f / 255, // y
1849 -25.6642f / 255, -86.3358f / 255, 112.f / 255, 128.f / 255, // u
1850 112.f / 255, -101.7303f / 255, -10.2697f / 255, 128.f / 255, // v
1851 };
1852 static constexpr float kJpegM[] {
1853 0.299f , 0.587f , 0.114f , 0.f / 255, // y
1854 -0.168736f, -0.331264f, 0.5f , 128.f / 255, // u
1855 0.5f , -0.418688f, -0.081312f, 128.f / 255, // v
1856 };
1857 static constexpr float kIM[] {
1858 1.f, 0.f, 0.f, 0.f,
1859 0.f, 1.f, 0.f, 0.f,
1860 0.f, 0.f, 1.f, 0.f,
1861 };
1862 const float* baseM = kIM;
1863 switch (yuvColorSpace) {
1864 case kRec601_SkYUVColorSpace:
1865 baseM = kRec601M;
1866 break;
1867 case kRec709_SkYUVColorSpace:
1868 baseM = kRec709M;
1869 break;
1870 case kJPEG_SkYUVColorSpace:
1871 baseM = kJpegM;
1872 break;
1873 case kIdentity_SkYUVColorSpace:
1874 baseM = kIM;
1875 break;
1876 }
1877 // TODO: Use one transfer buffer for all three planes to reduce map/unmap cost?
1878
1879 auto texMatrix = SkMatrix::MakeTrans(x, y);
1880
1881 SkRect dstRectY = SkRect::Make(dstSize);
1882 SkRect dstRectUV = SkRect::MakeWH(halfW, halfH);
1883
1884 // This matrix generates (r,g,b,a) = (0, 0, 0, y)
1885 float yM[20];
1886 std::fill_n(yM, 15, 0.f);
1887 yM[15] = baseM[0]; yM[16] = baseM[1]; yM[17] = baseM[2]; yM[18] = 0; yM[19] = baseM[3];
1888 GrPaint yPaint;
1889 yPaint.addColorTextureProcessor(srcProxy, srcColorType, texMatrix);
1890 auto yFP = GrColorMatrixFragmentProcessor::Make(yM, false, true, false);
1891 yPaint.addColorFragmentProcessor(std::move(yFP));
1892 yPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
1893 yRTC->fillRectToRect(GrNoClip(), std::move(yPaint), GrAA::kNo, SkMatrix::I(),
1894 dstRectY, dstRectY);
1895 auto yTransfer = yRTC->transferPixels(GrColorType::kAlpha_8,
1896 SkIRect::MakeWH(yRTC->width(), yRTC->height()));
1897 if (!yTransfer.fTransferBuffer) {
1898 callback(context, nullptr);
1899 return;
1900 }
1901
1902 texMatrix.preScale(2.f, 2.f);
1903 // This matrix generates (r,g,b,a) = (0, 0, 0, u)
1904 float uM[20];
1905 std::fill_n(uM, 15, 0.f);
1906 uM[15] = baseM[4]; uM[16] = baseM[5]; uM[17] = baseM[6]; uM[18] = 0; uM[19] = baseM[7];
1907 GrPaint uPaint;
1908 uPaint.addColorTextureProcessor(srcProxy, srcColorType, texMatrix,
1909 GrSamplerState::ClampBilerp());
1910 auto uFP = GrColorMatrixFragmentProcessor::Make(uM, false, true, false);
1911 uPaint.addColorFragmentProcessor(std::move(uFP));
1912 uPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
1913 uRTC->fillRectToRect(GrNoClip(), std::move(uPaint), GrAA::kNo, SkMatrix::I(),
1914 dstRectUV, dstRectUV);
1915 auto uTransfer = uRTC->transferPixels(GrColorType::kAlpha_8,
1916 SkIRect::MakeWH(uRTC->width(), uRTC->height()));
1917 if (!uTransfer.fTransferBuffer) {
1918 callback(context, nullptr);
1919 return;
1920 }
1921
1922 // This matrix generates (r,g,b,a) = (0, 0, 0, v)
1923 float vM[20];
1924 std::fill_n(vM, 15, 0.f);
1925 vM[15] = baseM[8]; vM[16] = baseM[9]; vM[17] = baseM[10]; vM[18] = 0; vM[19] = baseM[11];
1926 GrPaint vPaint;
1927 vPaint.addColorTextureProcessor(srcProxy, srcColorType, texMatrix,
1928 GrSamplerState::ClampBilerp());
1929 auto vFP = GrColorMatrixFragmentProcessor::Make(vM, false, true, false);
1930 vPaint.addColorFragmentProcessor(std::move(vFP));
1931 vPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
1932 vRTC->fillRectToRect(GrNoClip(), std::move(vPaint), GrAA::kNo, SkMatrix::I(),
1933 dstRectUV, dstRectUV);
1934 auto vTransfer = vRTC->transferPixels(GrColorType::kAlpha_8,
1935 SkIRect::MakeWH(vRTC->width(), vRTC->height()));
1936 if (!vTransfer.fTransferBuffer) {
1937 callback(context, nullptr);
1938 return;
1939 }
1940
1941 struct FinishContext {
1942 ReadPixelsCallback* fClientCallback;
1943 ReadPixelsContext fClientContext;
1944 GrClientMappedBufferManager* fMappedBufferManager;
1945 SkISize fSize;
1946 PixelTransferResult fYTransfer;
1947 PixelTransferResult fUTransfer;
1948 PixelTransferResult fVTransfer;
1949 };
1950 // Assumption is that the caller would like to flush. We could take a parameter or require an
1951 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
1952 // callback to GrGpu until after the next flush that flushes our op list, though.
1953 auto* finishContext = new FinishContext{callback,
1954 context,
1955 direct->priv().clientMappedBufferManager(),
1956 dstSize,
1957 std::move(yTransfer),
1958 std::move(uTransfer),
1959 std::move(vTransfer)};
1960 auto finishCallback = [](GrGpuFinishedContext c) {
1961 const auto* context = reinterpret_cast<const FinishContext*>(c);
1962 auto result = skstd::make_unique<AsyncReadResult>(context->fMappedBufferManager->inboxID());
1963 auto manager = context->fMappedBufferManager;
1964 size_t rowBytes = SkToSizeT(context->fSize.width());
1965 if (!result->addTransferResult(context->fYTransfer, context->fSize, rowBytes, manager)) {
1966 (*context->fClientCallback)(context->fClientContext, nullptr);
1967 delete context;
1968 return;
1969 }
1970 rowBytes /= 2;
1971 SkISize uvSize = {context->fSize.width()/2, context->fSize.height()/2};
1972 if (!result->addTransferResult(context->fUTransfer, uvSize, rowBytes, manager)) {
1973 (*context->fClientCallback)(context->fClientContext, nullptr);
1974 delete context;
1975 return;
1976 }
1977 if (!result->addTransferResult(context->fVTransfer, uvSize, rowBytes, manager)) {
1978 (*context->fClientCallback)(context->fClientContext, nullptr);
1979 delete context;
1980 return;
1981 }
1982 (*context->fClientCallback)(context->fClientContext, std::move(result));
1983 delete context;
1984 };
1985 GrFlushInfo flushInfo;
1986 flushInfo.fFinishedContext = finishContext;
1987 flushInfo.fFinishedProc = finishCallback;
1988 this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
1989 }
1990
flush(SkSurface::BackendSurfaceAccess access,const GrFlushInfo & info)1991 GrSemaphoresSubmitted GrRenderTargetContext::flush(SkSurface::BackendSurfaceAccess access,
1992 const GrFlushInfo& info) {
1993 ASSERT_SINGLE_OWNER
1994 if (fContext->priv().abandoned()) {
1995 return GrSemaphoresSubmitted::kNo;
1996 }
1997 SkDEBUGCODE(this->validate();)
1998 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "flush", fContext);
1999
2000 return this->drawingManager()->flushSurface(fRenderTargetProxy.get(), access, info);
2001 }
2002
waitOnSemaphores(int numSemaphores,const GrBackendSemaphore waitSemaphores[])2003 bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
2004 const GrBackendSemaphore waitSemaphores[]) {
2005 ASSERT_SINGLE_OWNER
2006 RETURN_FALSE_IF_ABANDONED
2007 SkDEBUGCODE(this->validate();)
2008 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "waitOnSemaphores", fContext);
2009
2010 AutoCheckFlush acf(this->drawingManager());
2011
2012 if (numSemaphores && !this->caps()->semaphoreSupport()) {
2013 return false;
2014 }
2015
2016 auto direct = fContext->priv().asDirectContext();
2017 if (!direct) {
2018 return false;
2019 }
2020
2021 auto resourceProvider = direct->priv().resourceProvider();
2022
2023 std::unique_ptr<sk_sp<GrSemaphore>[]> grSemaphores(new sk_sp<GrSemaphore>[numSemaphores]);
2024 for (int i = 0; i < numSemaphores; ++i) {
2025 grSemaphores[i] = resourceProvider->wrapBackendSemaphore(
2026 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
2027 kAdopt_GrWrapOwnership);
2028 }
2029 this->drawingManager()->newWaitRenderTask(this->asSurfaceProxyRef(), std::move(grSemaphores),
2030 numSemaphores);
2031 return true;
2032 }
2033
insertEventMarker(const SkString & str)2034 void GrRenderTargetContext::insertEventMarker(const SkString& str) {
2035 std::unique_ptr<GrOp> op(GrDebugMarkerOp::Make(fContext, fRenderTargetProxy.get(), str));
2036 this->addOp(std::move(op));
2037 }
2038
drawPath(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkPath & path,const GrStyle & style)2039 void GrRenderTargetContext::drawPath(const GrClip& clip,
2040 GrPaint&& paint,
2041 GrAA aa,
2042 const SkMatrix& viewMatrix,
2043 const SkPath& path,
2044 const GrStyle& style) {
2045 ASSERT_SINGLE_OWNER
2046 RETURN_IF_ABANDONED
2047 SkDEBUGCODE(this->validate();)
2048 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPath", fContext);
2049
2050 GrShape shape(path, style);
2051
2052 this->drawShape(clip, std::move(paint), aa, viewMatrix, shape);
2053 }
2054
drawShape(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const GrShape & shape)2055 void GrRenderTargetContext::drawShape(const GrClip& clip,
2056 GrPaint&& paint,
2057 GrAA aa,
2058 const SkMatrix& viewMatrix,
2059 const GrShape& shape) {
2060 ASSERT_SINGLE_OWNER
2061 RETURN_IF_ABANDONED
2062 SkDEBUGCODE(this->validate();)
2063 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawShape", fContext);
2064
2065 if (shape.isEmpty()) {
2066 if (shape.inverseFilled()) {
2067 this->drawPaint(clip, std::move(paint), viewMatrix);
2068 }
2069 return;
2070 }
2071
2072 AutoCheckFlush acf(this->drawingManager());
2073
2074 if (!shape.style().hasPathEffect()) {
2075 GrAAType aaType = this->chooseAAType(aa);
2076 SkRRect rrect;
2077 // We can ignore the starting point and direction since there is no path effect.
2078 bool inverted;
2079 if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) {
2080 if (rrect.isRect()) {
2081 this->drawRect(clip, std::move(paint), aa, viewMatrix, rrect.rect(),
2082 &shape.style());
2083 return;
2084 } else if (rrect.isOval()) {
2085 this->drawOval(clip, std::move(paint), aa, viewMatrix, rrect.rect(), shape.style());
2086 return;
2087 }
2088 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, shape.style());
2089 return;
2090 } else if (GrAAType::kCoverage == aaType && shape.style().isSimpleFill() &&
2091 viewMatrix.rectStaysRect()) {
2092 // TODO: the rectStaysRect restriction could be lifted if we were willing to apply
2093 // the matrix to all the points individually rather than just to the rect
2094 SkRect rects[2];
2095 if (shape.asNestedRects(rects)) {
2096 // Concave AA paths are expensive - try to avoid them for special cases
2097 std::unique_ptr<GrDrawOp> op = GrStrokeRectOp::MakeNested(
2098 fContext, std::move(paint), viewMatrix, rects);
2099 if (op) {
2100 this->addDrawOp(clip, std::move(op));
2101 }
2102 // Returning here indicates that there is nothing to draw in this case.
2103 return;
2104 }
2105 }
2106 }
2107
2108 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape);
2109 }
2110
drawAndStencilPath(const GrHardClip & clip,const GrUserStencilSettings * ss,SkRegion::Op op,bool invert,GrAA aa,const SkMatrix & viewMatrix,const SkPath & path)2111 bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
2112 const GrUserStencilSettings* ss,
2113 SkRegion::Op op,
2114 bool invert,
2115 GrAA aa,
2116 const SkMatrix& viewMatrix,
2117 const SkPath& path) {
2118 ASSERT_SINGLE_OWNER_PRIV
2119 RETURN_FALSE_IF_ABANDONED_PRIV
2120 SkDEBUGCODE(fRenderTargetContext->validate();)
2121 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilPath",
2122 fRenderTargetContext->fContext);
2123
2124 if (path.isEmpty() && path.isInverseFillType()) {
2125 GrPaint paint;
2126 paint.setCoverageSetOpXPFactory(op, invert);
2127 this->stencilRect(clip, ss, std::move(paint), GrAA::kNo, SkMatrix::I(),
2128 SkRect::MakeIWH(fRenderTargetContext->width(),
2129 fRenderTargetContext->height()));
2130 return true;
2131 }
2132
2133 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
2134
2135 // An Assumption here is that path renderer would use some form of tweaking
2136 // the src color (either the input alpha or in the frag shader) to implement
2137 // aa. If we have some future driver-mojo path AA that can do the right
2138 // thing WRT to the blend then we'll need some query on the PR.
2139 GrAAType aaType = fRenderTargetContext->chooseAAType(aa);
2140 bool hasUserStencilSettings = !ss->isUnused();
2141
2142 SkIRect clipConservativeBounds;
2143 clip.getConservativeBounds(fRenderTargetContext->width(), fRenderTargetContext->height(),
2144 &clipConservativeBounds, nullptr);
2145
2146 GrShape shape(path, GrStyle::SimpleFill());
2147 GrPathRenderer::CanDrawPathArgs canDrawArgs;
2148 canDrawArgs.fCaps = fRenderTargetContext->caps();
2149 canDrawArgs.fProxy = fRenderTargetContext->proxy();
2150 canDrawArgs.fViewMatrix = &viewMatrix;
2151 canDrawArgs.fShape = &shape;
2152 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
2153 canDrawArgs.fAAType = aaType;
2154 SkASSERT(!fRenderTargetContext->wrapsVkSecondaryCB());
2155 canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
2156 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
2157
2158 // Don't allow the SW renderer
2159 GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer(
2160 canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor);
2161 if (!pr) {
2162 return false;
2163 }
2164
2165 GrPaint paint;
2166 paint.setCoverageSetOpXPFactory(op, invert);
2167
2168 GrPathRenderer::DrawPathArgs args{fRenderTargetContext->drawingManager()->getContext(),
2169 std::move(paint),
2170 ss,
2171 fRenderTargetContext,
2172 &clip,
2173 &clipConservativeBounds,
2174 &viewMatrix,
2175 &shape,
2176 aaType,
2177 fRenderTargetContext->colorInfo().isLinearlyBlended()};
2178 pr->drawPath(args);
2179 return true;
2180 }
2181
isBudgeted() const2182 SkBudgeted GrRenderTargetContextPriv::isBudgeted() const {
2183 ASSERT_SINGLE_OWNER_PRIV
2184
2185 if (fRenderTargetContext->fContext->priv().abandoned()) {
2186 return SkBudgeted::kNo;
2187 }
2188
2189 SkDEBUGCODE(fRenderTargetContext->validate();)
2190
2191 return fRenderTargetContext->fRenderTargetProxy->isBudgeted();
2192 }
2193
drawShapeUsingPathRenderer(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const GrShape & originalShape)2194 void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
2195 GrPaint&& paint,
2196 GrAA aa,
2197 const SkMatrix& viewMatrix,
2198 const GrShape& originalShape) {
2199 ASSERT_SINGLE_OWNER
2200 RETURN_IF_ABANDONED
2201 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext);
2202
2203 if (!viewMatrix.isFinite() || !originalShape.bounds().isFinite()) {
2204 return;
2205 }
2206
2207 SkIRect clipConservativeBounds;
2208 clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);
2209
2210 GrShape tempShape;
2211 GrAAType aaType = this->chooseAAType(aa);
2212
2213 GrPathRenderer::CanDrawPathArgs canDrawArgs;
2214 canDrawArgs.fCaps = this->caps();
2215 canDrawArgs.fProxy = this->proxy();
2216 canDrawArgs.fViewMatrix = &viewMatrix;
2217 canDrawArgs.fShape = &originalShape;
2218 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
2219 canDrawArgs.fTargetIsWrappedVkSecondaryCB = this->wrapsVkSecondaryCB();
2220 canDrawArgs.fHasUserStencilSettings = false;
2221
2222 GrPathRenderer* pr;
2223 static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor;
2224 if (originalShape.isEmpty() && !originalShape.inverseFilled()) {
2225 return;
2226 }
2227
2228 canDrawArgs.fAAType = aaType;
2229
2230 // Try a 1st time without applying any of the style to the geometry (and barring sw)
2231 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
2232 SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix);
2233
2234 if (!pr && originalShape.style().pathEffect()) {
2235 // It didn't work above, so try again with the path effect applied.
2236 tempShape = originalShape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
2237 if (tempShape.isEmpty()) {
2238 return;
2239 }
2240 canDrawArgs.fShape = &tempShape;
2241 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
2242 }
2243 if (!pr) {
2244 if (canDrawArgs.fShape->style().applies()) {
2245 tempShape = canDrawArgs.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec,
2246 styleScale);
2247 if (tempShape.isEmpty()) {
2248 return;
2249 }
2250 canDrawArgs.fShape = &tempShape;
2251 // This time, allow SW renderer
2252 pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType);
2253 } else {
2254 pr = this->drawingManager()->getSoftwarePathRenderer();
2255 }
2256 }
2257
2258 if (!pr) {
2259 #ifdef SK_DEBUG
2260 SkDebugf("Unable to find path renderer compatible with path.\n");
2261 #endif
2262 return;
2263 }
2264
2265 GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
2266 std::move(paint),
2267 &GrUserStencilSettings::kUnused,
2268 this,
2269 &clip,
2270 &clipConservativeBounds,
2271 &viewMatrix,
2272 canDrawArgs.fShape,
2273 aaType,
2274 this->colorInfo().isLinearlyBlended()};
2275 pr->drawPath(args);
2276 }
2277
op_bounds(SkRect * bounds,const GrOp * op)2278 static void op_bounds(SkRect* bounds, const GrOp* op) {
2279 *bounds = op->bounds();
2280 if (op->hasZeroArea()) {
2281 if (op->hasAABloat()) {
2282 bounds->outset(0.5f, 0.5f);
2283 } else {
2284 // We don't know which way the particular GPU will snap lines or points at integer
2285 // coords. So we ensure that the bounds is large enough for either snap.
2286 SkRect before = *bounds;
2287 bounds->roundOut(bounds);
2288 if (bounds->fLeft == before.fLeft) {
2289 bounds->fLeft -= 1;
2290 }
2291 if (bounds->fTop == before.fTop) {
2292 bounds->fTop -= 1;
2293 }
2294 if (bounds->fRight == before.fRight) {
2295 bounds->fRight += 1;
2296 }
2297 if (bounds->fBottom == before.fBottom) {
2298 bounds->fBottom += 1;
2299 }
2300 }
2301 }
2302 }
2303
addOp(std::unique_ptr<GrOp> op)2304 void GrRenderTargetContext::addOp(std::unique_ptr<GrOp> op) {
2305 this->getOpsTask()->addOp(
2306 std::move(op), GrTextureResolveManager(this->drawingManager()), *this->caps());
2307 }
2308
addDrawOp(const GrClip & clip,std::unique_ptr<GrDrawOp> op,const std::function<WillAddOpFn> & willAddFn)2309 void GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op,
2310 const std::function<WillAddOpFn>& willAddFn) {
2311 ASSERT_SINGLE_OWNER
2312 if (fContext->priv().abandoned()) {
2313 fContext->priv().opMemoryPool()->release(std::move(op));
2314 return;
2315 }
2316 SkDEBUGCODE(this->validate();)
2317 SkDEBUGCODE(op->fAddDrawOpCalled = true;)
2318 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "addDrawOp", fContext);
2319
2320 // Setup clip
2321 SkRect bounds;
2322 op_bounds(&bounds, op.get());
2323 GrAppliedClip appliedClip;
2324 GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags();
2325 bool usesHWAA = fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA;
2326 bool usesStencil = fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil;
2327
2328 if (usesStencil) {
2329 this->setNeedsStencil(usesHWAA);
2330 }
2331
2332 if (!clip.apply(fContext, this, usesHWAA, usesStencil, &appliedClip, &bounds)) {
2333 fContext->priv().opMemoryPool()->release(std::move(op));
2334 return;
2335 }
2336
2337 SkASSERT((!usesStencil && !appliedClip.hasStencilClip()) || (fNumStencilSamples > 0));
2338
2339 GrClampType clampType = GrColorTypeClampType(this->colorInfo().colorType());
2340 // MIXED SAMPLES TODO: If we start using mixed samples for clips we will need to check the clip
2341 // here as well.
2342 bool hasMixedSampledCoverage = (usesHWAA && this->numSamples() <= 1);
2343 #ifdef SK_DEBUG
2344 if (hasMixedSampledCoverage) {
2345 SkASSERT(usesStencil);
2346 SkASSERT(fRenderTargetProxy->canUseMixedSamples(*this->caps()));
2347 }
2348 #endif
2349 GrProcessorSet::Analysis analysis = op->finalize(
2350 *this->caps(), &appliedClip, hasMixedSampledCoverage, clampType);
2351
2352 GrXferProcessor::DstProxy dstProxy;
2353 if (analysis.requiresDstTexture()) {
2354 if (!this->setupDstProxy(clip, *op, &dstProxy)) {
2355 fContext->priv().opMemoryPool()->release(std::move(op));
2356 return;
2357 }
2358 }
2359
2360 op->setClippedBounds(bounds);
2361 auto opsTask = this->getOpsTask();
2362 if (willAddFn) {
2363 willAddFn(op.get(), opsTask->uniqueID());
2364 }
2365 opsTask->addDrawOp(std::move(op), analysis, std::move(appliedClip), dstProxy,
2366 GrTextureResolveManager(this->drawingManager()), *this->caps());
2367 }
2368
setupDstProxy(const GrClip & clip,const GrOp & op,GrXferProcessor::DstProxy * dstProxy)2369 bool GrRenderTargetContext::setupDstProxy(const GrClip& clip, const GrOp& op,
2370 GrXferProcessor::DstProxy* dstProxy) {
2371 // If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we
2372 // don't actually have a VkImage to make a copy of. Additionally we don't have the power to
2373 // start and stop the render pass in order to make the copy.
2374 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
2375 return false;
2376 }
2377
2378 if (this->caps()->textureBarrierSupport() && !fRenderTargetProxy->requiresManualMSAAResolve()) {
2379 if (GrTextureProxy* texProxy = fRenderTargetProxy->asTextureProxy()) {
2380 // The render target is a texture, so we can read from it directly in the shader. The XP
2381 // will be responsible to detect this situation and request a texture barrier.
2382 dstProxy->setProxy(sk_ref_sp(texProxy));
2383 dstProxy->setOffset(0, 0);
2384 return true;
2385 }
2386 }
2387
2388 SkIRect copyRect = SkIRect::MakeWH(fRenderTargetProxy->width(), fRenderTargetProxy->height());
2389
2390 SkIRect clippedRect;
2391 clip.getConservativeBounds(
2392 fRenderTargetProxy->width(), fRenderTargetProxy->height(), &clippedRect);
2393 SkRect opBounds = op.bounds();
2394 // If the op has aa bloating or is a infinitely thin geometry (hairline) outset the bounds by
2395 // 0.5 pixels.
2396 if (op.hasAABloat() || op.hasZeroArea()) {
2397 opBounds.outset(0.5f, 0.5f);
2398 // An antialiased/hairline draw can sometimes bleed outside of the clips bounds. For
2399 // performance we may ignore the clip when the draw is entirely inside the clip is float
2400 // space but will hit pixels just outside the clip when actually rasterizing.
2401 clippedRect.outset(1, 1);
2402 clippedRect.intersect(SkIRect::MakeWH(
2403 fRenderTargetProxy->width(), fRenderTargetProxy->height()));
2404 }
2405 SkIRect opIBounds;
2406 opBounds.roundOut(&opIBounds);
2407 if (!clippedRect.intersect(opIBounds)) {
2408 #ifdef SK_DEBUG
2409 GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw.");
2410 #endif
2411 return false;
2412 }
2413
2414 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
2415 // have per-sample dst values by making the copy multisampled.
2416 GrCaps::DstCopyRestrictions restrictions = this->caps()->getDstCopyRestrictions(
2417 fRenderTargetProxy.get(), this->colorInfo().colorType());
2418
2419 if (!restrictions.fMustCopyWholeSrc) {
2420 copyRect = clippedRect;
2421 }
2422
2423 SkIPoint dstOffset;
2424 SkBackingFit fit;
2425 if (restrictions.fRectsMustMatch == GrSurfaceProxy::RectsMustMatch::kYes) {
2426 dstOffset = {0, 0};
2427 fit = SkBackingFit::kExact;
2428 } else {
2429 dstOffset = {copyRect.fLeft, copyRect.fTop};
2430 fit = SkBackingFit::kApprox;
2431 }
2432 sk_sp<GrTextureProxy> newProxy = GrSurfaceProxy::Copy(
2433 fContext, fRenderTargetProxy.get(), this->colorInfo().colorType(), GrMipMapped::kNo,
2434 copyRect, fit, SkBudgeted::kYes, restrictions.fRectsMustMatch);
2435 SkASSERT(newProxy);
2436
2437 dstProxy->setProxy(std::move(newProxy));
2438 dstProxy->setOffset(dstOffset);
2439 return true;
2440 }
2441
blitTexture(GrTextureProxy * src,GrColorType srcColorType,const SkIRect & srcRect,const SkIPoint & dstPoint)2442 bool GrRenderTargetContext::blitTexture(GrTextureProxy* src, GrColorType srcColorType,
2443 const SkIRect& srcRect, const SkIPoint& dstPoint) {
2444 SkIRect clippedSrcRect;
2445 SkIPoint clippedDstPoint;
2446 if (!GrClipSrcRectAndDstPoint(this->asSurfaceProxy()->isize(), src->isize(), srcRect, dstPoint,
2447 &clippedSrcRect, &clippedDstPoint)) {
2448 return false;
2449 }
2450
2451 GrPaint paint;
2452 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
2453 auto fp = GrSimpleTextureEffect::Make(sk_ref_sp(src), srcColorType, SkMatrix::I());
2454 if (!fp) {
2455 return false;
2456 }
2457 paint.addColorFragmentProcessor(std::move(fp));
2458
2459 this->fillRectToRect(
2460 GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
2461 SkRect::MakeXYWH(clippedDstPoint.fX, clippedDstPoint.fY, clippedSrcRect.width(),
2462 clippedSrcRect.height()),
2463 SkRect::Make(clippedSrcRect));
2464 return true;
2465 }
2466
2467