1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2015 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSamplingOptions.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrContextOptions.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkPoint_impl.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTPin.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrImageContext.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTLazy.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkSpecialImage.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/Swizzle.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/TiledTextureUtils.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/Device.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrBlurUtils.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColorInfo.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColorSpaceXform.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFPArgs.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFragmentProcessor.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrFragmentProcessors.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpsTypes.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPaint.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSamplerState.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxy.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxyView.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTextureProxy.h"
52*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SkGr.h"
53*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SurfaceDrawContext.h"
54*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrBlendFragmentProcessor.h"
55*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrTextureEffect.h"
56*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrRect.h"
57*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrStyledShape.h"
58*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/image/GrImageUtils.h"
59*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/image/SkImage_Ganesh.h"
60*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/image/SkSpecialImage_Ganesh.h"
61*c8dee2aaSAndroid Build Coastguard Worker #include "src/image/SkImage_Base.h"
62*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkShaderBase.h"
63*c8dee2aaSAndroid Build Coastguard Worker
64*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
65*c8dee2aaSAndroid Build Coastguard Worker #include <tuple>
66*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
67*c8dee2aaSAndroid Build Coastguard Worker
68*c8dee2aaSAndroid Build Coastguard Worker class GrClip;
69*c8dee2aaSAndroid Build Coastguard Worker class SkMaskFilter;
70*c8dee2aaSAndroid Build Coastguard Worker
71*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
72*c8dee2aaSAndroid Build Coastguard Worker
73*c8dee2aaSAndroid Build Coastguard Worker namespace {
74*c8dee2aaSAndroid Build Coastguard Worker
use_shader(bool textureIsAlphaOnly,const SkPaint & paint)75*c8dee2aaSAndroid Build Coastguard Worker inline bool use_shader(bool textureIsAlphaOnly, const SkPaint& paint) {
76*c8dee2aaSAndroid Build Coastguard Worker return textureIsAlphaOnly && paint.getShader();
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker
79*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
80*c8dee2aaSAndroid Build Coastguard Worker // Helper functions for dropping src rect subset with GrSamplerState::Filter::kLinear.
81*c8dee2aaSAndroid Build Coastguard Worker
82*c8dee2aaSAndroid Build Coastguard Worker static const SkScalar kColorBleedTolerance = 0.001f;
83*c8dee2aaSAndroid Build Coastguard Worker
has_aligned_samples(const SkRect & srcRect,const SkRect & transformedRect)84*c8dee2aaSAndroid Build Coastguard Worker bool has_aligned_samples(const SkRect& srcRect, const SkRect& transformedRect) {
85*c8dee2aaSAndroid Build Coastguard Worker // detect pixel disalignment
86*c8dee2aaSAndroid Build Coastguard Worker if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) - transformedRect.left()) < kColorBleedTolerance &&
87*c8dee2aaSAndroid Build Coastguard Worker SkScalarAbs(SkScalarRoundToScalar(transformedRect.top()) - transformedRect.top()) < kColorBleedTolerance &&
88*c8dee2aaSAndroid Build Coastguard Worker SkScalarAbs(transformedRect.width() - srcRect.width()) < kColorBleedTolerance &&
89*c8dee2aaSAndroid Build Coastguard Worker SkScalarAbs(transformedRect.height() - srcRect.height()) < kColorBleedTolerance) {
90*c8dee2aaSAndroid Build Coastguard Worker return true;
91*c8dee2aaSAndroid Build Coastguard Worker }
92*c8dee2aaSAndroid Build Coastguard Worker return false;
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker
may_color_bleed(const SkRect & srcRect,const SkRect & transformedRect,const SkMatrix & m,int numSamples)95*c8dee2aaSAndroid Build Coastguard Worker bool may_color_bleed(const SkRect& srcRect,
96*c8dee2aaSAndroid Build Coastguard Worker const SkRect& transformedRect,
97*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& m,
98*c8dee2aaSAndroid Build Coastguard Worker int numSamples) {
99*c8dee2aaSAndroid Build Coastguard Worker // Only gets called if has_aligned_samples returned false.
100*c8dee2aaSAndroid Build Coastguard Worker // So we can assume that sampling is axis aligned but not texel aligned.
101*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!has_aligned_samples(srcRect, transformedRect));
102*c8dee2aaSAndroid Build Coastguard Worker SkRect innerSrcRect(srcRect), innerTransformedRect, outerTransformedRect(transformedRect);
103*c8dee2aaSAndroid Build Coastguard Worker if (numSamples > 1) {
104*c8dee2aaSAndroid Build Coastguard Worker innerSrcRect.inset(SK_Scalar1, SK_Scalar1);
105*c8dee2aaSAndroid Build Coastguard Worker } else {
106*c8dee2aaSAndroid Build Coastguard Worker innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf);
107*c8dee2aaSAndroid Build Coastguard Worker }
108*c8dee2aaSAndroid Build Coastguard Worker m.mapRect(&innerTransformedRect, innerSrcRect);
109*c8dee2aaSAndroid Build Coastguard Worker
110*c8dee2aaSAndroid Build Coastguard Worker // The gap between outerTransformedRect and innerTransformedRect
111*c8dee2aaSAndroid Build Coastguard Worker // represents the projection of the source border area, which is
112*c8dee2aaSAndroid Build Coastguard Worker // problematic for color bleeding. We must check whether any
113*c8dee2aaSAndroid Build Coastguard Worker // destination pixels sample the border area.
114*c8dee2aaSAndroid Build Coastguard Worker outerTransformedRect.inset(kColorBleedTolerance, kColorBleedTolerance);
115*c8dee2aaSAndroid Build Coastguard Worker innerTransformedRect.outset(kColorBleedTolerance, kColorBleedTolerance);
116*c8dee2aaSAndroid Build Coastguard Worker SkIRect outer, inner;
117*c8dee2aaSAndroid Build Coastguard Worker outerTransformedRect.round(&outer);
118*c8dee2aaSAndroid Build Coastguard Worker innerTransformedRect.round(&inner);
119*c8dee2aaSAndroid Build Coastguard Worker // If the inner and outer rects round to the same result, it means the
120*c8dee2aaSAndroid Build Coastguard Worker // border does not overlap any pixel centers. Yay!
121*c8dee2aaSAndroid Build Coastguard Worker return inner != outer;
122*c8dee2aaSAndroid Build Coastguard Worker }
123*c8dee2aaSAndroid Build Coastguard Worker
can_ignore_linear_filtering_subset(const SkRect & srcSubset,const SkMatrix & srcRectToDeviceSpace,int numSamples)124*c8dee2aaSAndroid Build Coastguard Worker bool can_ignore_linear_filtering_subset(const SkRect& srcSubset,
125*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& srcRectToDeviceSpace,
126*c8dee2aaSAndroid Build Coastguard Worker int numSamples) {
127*c8dee2aaSAndroid Build Coastguard Worker if (srcRectToDeviceSpace.rectStaysRect()) {
128*c8dee2aaSAndroid Build Coastguard Worker // sampling is axis-aligned
129*c8dee2aaSAndroid Build Coastguard Worker SkRect transformedRect;
130*c8dee2aaSAndroid Build Coastguard Worker srcRectToDeviceSpace.mapRect(&transformedRect, srcSubset);
131*c8dee2aaSAndroid Build Coastguard Worker
132*c8dee2aaSAndroid Build Coastguard Worker if (has_aligned_samples(srcSubset, transformedRect) ||
133*c8dee2aaSAndroid Build Coastguard Worker !may_color_bleed(srcSubset, transformedRect, srcRectToDeviceSpace, numSamples)) {
134*c8dee2aaSAndroid Build Coastguard Worker return true;
135*c8dee2aaSAndroid Build Coastguard Worker }
136*c8dee2aaSAndroid Build Coastguard Worker }
137*c8dee2aaSAndroid Build Coastguard Worker return false;
138*c8dee2aaSAndroid Build Coastguard Worker }
139*c8dee2aaSAndroid Build Coastguard Worker
140*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
141*c8dee2aaSAndroid Build Coastguard Worker // Helper functions for drawing an image with ganesh::SurfaceDrawContext
142*c8dee2aaSAndroid Build Coastguard Worker
143*c8dee2aaSAndroid Build Coastguard Worker /**
144*c8dee2aaSAndroid Build Coastguard Worker * Checks whether the paint is compatible with using SurfaceDrawContext::drawTexture. It is more
145*c8dee2aaSAndroid Build Coastguard Worker * efficient than the SkImage general case.
146*c8dee2aaSAndroid Build Coastguard Worker */
can_use_draw_texture(const SkPaint & paint,const SkSamplingOptions & sampling)147*c8dee2aaSAndroid Build Coastguard Worker bool can_use_draw_texture(const SkPaint& paint, const SkSamplingOptions& sampling) {
148*c8dee2aaSAndroid Build Coastguard Worker return (!paint.getColorFilter() && !paint.getShader() && !paint.getMaskFilter() &&
149*c8dee2aaSAndroid Build Coastguard Worker !paint.getImageFilter() && !paint.getBlender() && !sampling.isAniso() &&
150*c8dee2aaSAndroid Build Coastguard Worker !sampling.useCubic && sampling.mipmap == SkMipmapMode::kNone);
151*c8dee2aaSAndroid Build Coastguard Worker }
152*c8dee2aaSAndroid Build Coastguard Worker
texture_color(SkColor4f paintColor,float entryAlpha,GrColorType srcColorType,const GrColorInfo & dstColorInfo)153*c8dee2aaSAndroid Build Coastguard Worker SkPMColor4f texture_color(SkColor4f paintColor, float entryAlpha, GrColorType srcColorType,
154*c8dee2aaSAndroid Build Coastguard Worker const GrColorInfo& dstColorInfo) {
155*c8dee2aaSAndroid Build Coastguard Worker paintColor.fA *= entryAlpha;
156*c8dee2aaSAndroid Build Coastguard Worker if (GrColorTypeIsAlphaOnly(srcColorType)) {
157*c8dee2aaSAndroid Build Coastguard Worker return SkColor4fPrepForDst(paintColor, dstColorInfo).premul();
158*c8dee2aaSAndroid Build Coastguard Worker } else {
159*c8dee2aaSAndroid Build Coastguard Worker float paintAlpha = SkTPin(paintColor.fA, 0.f, 1.f);
160*c8dee2aaSAndroid Build Coastguard Worker return { paintAlpha, paintAlpha, paintAlpha, paintAlpha };
161*c8dee2aaSAndroid Build Coastguard Worker }
162*c8dee2aaSAndroid Build Coastguard Worker }
163*c8dee2aaSAndroid Build Coastguard Worker
164*c8dee2aaSAndroid Build Coastguard Worker // Assumes srcRect and dstRect have already been optimized to fit the proxy
draw_texture(skgpu::ganesh::SurfaceDrawContext * sdc,const GrClip * clip,const SkMatrix & ctm,const SkPaint & paint,GrSamplerState::Filter filter,const SkRect & srcRect,const SkRect & dstRect,const SkPoint dstClip[4],GrQuadAAFlags aaFlags,SkCanvas::SrcRectConstraint constraint,GrSurfaceProxyView view,const GrColorInfo & srcColorInfo)165*c8dee2aaSAndroid Build Coastguard Worker void draw_texture(skgpu::ganesh::SurfaceDrawContext* sdc,
166*c8dee2aaSAndroid Build Coastguard Worker const GrClip* clip,
167*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& ctm,
168*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
169*c8dee2aaSAndroid Build Coastguard Worker GrSamplerState::Filter filter,
170*c8dee2aaSAndroid Build Coastguard Worker const SkRect& srcRect,
171*c8dee2aaSAndroid Build Coastguard Worker const SkRect& dstRect,
172*c8dee2aaSAndroid Build Coastguard Worker const SkPoint dstClip[4],
173*c8dee2aaSAndroid Build Coastguard Worker GrQuadAAFlags aaFlags,
174*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::SrcRectConstraint constraint,
175*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxyView view,
176*c8dee2aaSAndroid Build Coastguard Worker const GrColorInfo& srcColorInfo) {
177*c8dee2aaSAndroid Build Coastguard Worker if (GrColorTypeIsAlphaOnly(srcColorInfo.colorType())) {
178*c8dee2aaSAndroid Build Coastguard Worker view.concatSwizzle(skgpu::Swizzle("aaaa"));
179*c8dee2aaSAndroid Build Coastguard Worker }
180*c8dee2aaSAndroid Build Coastguard Worker const GrColorInfo& dstInfo = sdc->colorInfo();
181*c8dee2aaSAndroid Build Coastguard Worker auto textureXform = GrColorSpaceXform::Make(srcColorInfo, sdc->colorInfo());
182*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxy* proxy = view.proxy();
183*c8dee2aaSAndroid Build Coastguard Worker // Must specify the strict constraint when the proxy is not functionally exact and the src
184*c8dee2aaSAndroid Build Coastguard Worker // rect would access pixels outside the proxy's content area without the constraint.
185*c8dee2aaSAndroid Build Coastguard Worker if (constraint != SkCanvas::kStrict_SrcRectConstraint && !proxy->isFunctionallyExact()) {
186*c8dee2aaSAndroid Build Coastguard Worker // Conservative estimate of how much a coord could be outset from src rect:
187*c8dee2aaSAndroid Build Coastguard Worker // 1/2 pixel for AA and 1/2 pixel for linear filtering
188*c8dee2aaSAndroid Build Coastguard Worker float buffer = 0.5f * (aaFlags != GrQuadAAFlags::kNone) +
189*c8dee2aaSAndroid Build Coastguard Worker GrTextureEffect::kLinearInset * (filter == GrSamplerState::Filter::kLinear);
190*c8dee2aaSAndroid Build Coastguard Worker SkRect safeBounds = proxy->getBoundsRect();
191*c8dee2aaSAndroid Build Coastguard Worker safeBounds.inset(buffer, buffer);
192*c8dee2aaSAndroid Build Coastguard Worker if (!safeBounds.contains(srcRect)) {
193*c8dee2aaSAndroid Build Coastguard Worker constraint = SkCanvas::kStrict_SrcRectConstraint;
194*c8dee2aaSAndroid Build Coastguard Worker }
195*c8dee2aaSAndroid Build Coastguard Worker }
196*c8dee2aaSAndroid Build Coastguard Worker
197*c8dee2aaSAndroid Build Coastguard Worker SkPMColor4f color = texture_color(paint.getColor4f(), 1.f, srcColorInfo.colorType(), dstInfo);
198*c8dee2aaSAndroid Build Coastguard Worker if (dstClip) {
199*c8dee2aaSAndroid Build Coastguard Worker // Get source coords corresponding to dstClip
200*c8dee2aaSAndroid Build Coastguard Worker SkPoint srcQuad[4];
201*c8dee2aaSAndroid Build Coastguard Worker GrMapRectPoints(dstRect, srcRect, dstClip, srcQuad, 4);
202*c8dee2aaSAndroid Build Coastguard Worker
203*c8dee2aaSAndroid Build Coastguard Worker sdc->drawTextureQuad(clip,
204*c8dee2aaSAndroid Build Coastguard Worker std::move(view),
205*c8dee2aaSAndroid Build Coastguard Worker srcColorInfo.colorType(),
206*c8dee2aaSAndroid Build Coastguard Worker srcColorInfo.alphaType(),
207*c8dee2aaSAndroid Build Coastguard Worker filter,
208*c8dee2aaSAndroid Build Coastguard Worker GrSamplerState::MipmapMode::kNone,
209*c8dee2aaSAndroid Build Coastguard Worker paint.getBlendMode_or(SkBlendMode::kSrcOver),
210*c8dee2aaSAndroid Build Coastguard Worker color,
211*c8dee2aaSAndroid Build Coastguard Worker srcQuad,
212*c8dee2aaSAndroid Build Coastguard Worker dstClip,
213*c8dee2aaSAndroid Build Coastguard Worker aaFlags,
214*c8dee2aaSAndroid Build Coastguard Worker constraint == SkCanvas::kStrict_SrcRectConstraint ? &srcRect : nullptr,
215*c8dee2aaSAndroid Build Coastguard Worker ctm,
216*c8dee2aaSAndroid Build Coastguard Worker std::move(textureXform));
217*c8dee2aaSAndroid Build Coastguard Worker } else {
218*c8dee2aaSAndroid Build Coastguard Worker sdc->drawTexture(clip,
219*c8dee2aaSAndroid Build Coastguard Worker std::move(view),
220*c8dee2aaSAndroid Build Coastguard Worker srcColorInfo.alphaType(),
221*c8dee2aaSAndroid Build Coastguard Worker filter,
222*c8dee2aaSAndroid Build Coastguard Worker GrSamplerState::MipmapMode::kNone,
223*c8dee2aaSAndroid Build Coastguard Worker paint.getBlendMode_or(SkBlendMode::kSrcOver),
224*c8dee2aaSAndroid Build Coastguard Worker color,
225*c8dee2aaSAndroid Build Coastguard Worker srcRect,
226*c8dee2aaSAndroid Build Coastguard Worker dstRect,
227*c8dee2aaSAndroid Build Coastguard Worker aaFlags,
228*c8dee2aaSAndroid Build Coastguard Worker constraint,
229*c8dee2aaSAndroid Build Coastguard Worker ctm,
230*c8dee2aaSAndroid Build Coastguard Worker std::move(textureXform));
231*c8dee2aaSAndroid Build Coastguard Worker }
232*c8dee2aaSAndroid Build Coastguard Worker }
233*c8dee2aaSAndroid Build Coastguard Worker
downgrade_to_filter(const SkSamplingOptions & sampling)234*c8dee2aaSAndroid Build Coastguard Worker SkFilterMode downgrade_to_filter(const SkSamplingOptions& sampling) {
235*c8dee2aaSAndroid Build Coastguard Worker SkFilterMode filter = sampling.filter;
236*c8dee2aaSAndroid Build Coastguard Worker if (sampling.isAniso() || sampling.useCubic || sampling.mipmap != SkMipmapMode::kNone) {
237*c8dee2aaSAndroid Build Coastguard Worker // if we were "fancier" than just bilerp, only do bilerp
238*c8dee2aaSAndroid Build Coastguard Worker filter = SkFilterMode::kLinear;
239*c8dee2aaSAndroid Build Coastguard Worker }
240*c8dee2aaSAndroid Build Coastguard Worker return filter;
241*c8dee2aaSAndroid Build Coastguard Worker }
242*c8dee2aaSAndroid Build Coastguard Worker
243*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
244*c8dee2aaSAndroid Build Coastguard Worker
245*c8dee2aaSAndroid Build Coastguard Worker
246*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
247*c8dee2aaSAndroid Build Coastguard Worker
248*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
249*c8dee2aaSAndroid Build Coastguard Worker
drawEdgeAAImage(const SkImage * image,const SkRect & src,const SkRect & dst,const SkPoint dstClip[4],SkCanvas::QuadAAFlags canvasAAFlags,const SkMatrix & localToDevice,const SkSamplingOptions & sampling,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint,const SkMatrix & srcToDst,SkTileMode tm)250*c8dee2aaSAndroid Build Coastguard Worker void Device::drawEdgeAAImage(const SkImage* image,
251*c8dee2aaSAndroid Build Coastguard Worker const SkRect& src,
252*c8dee2aaSAndroid Build Coastguard Worker const SkRect& dst,
253*c8dee2aaSAndroid Build Coastguard Worker const SkPoint dstClip[4],
254*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::QuadAAFlags canvasAAFlags,
255*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& localToDevice,
256*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions& sampling,
257*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
258*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::SrcRectConstraint constraint,
259*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& srcToDst,
260*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tm) {
261*c8dee2aaSAndroid Build Coastguard Worker GrRecordingContext* rContext = fContext.get();
262*c8dee2aaSAndroid Build Coastguard Worker SurfaceDrawContext* sdc = fSurfaceDrawContext.get();
263*c8dee2aaSAndroid Build Coastguard Worker const GrClip* clip = this->clip();
264*c8dee2aaSAndroid Build Coastguard Worker
265*c8dee2aaSAndroid Build Coastguard Worker GrQuadAAFlags aaFlags = SkToGrQuadAAFlags(canvasAAFlags);
266*c8dee2aaSAndroid Build Coastguard Worker auto ib = as_IB(image);
267*c8dee2aaSAndroid Build Coastguard Worker if (tm == SkTileMode::kClamp && !ib->isYUVA() && can_use_draw_texture(paint, sampling)) {
268*c8dee2aaSAndroid Build Coastguard Worker // We've done enough checks above to allow us to pass ClampNearest() and not check for
269*c8dee2aaSAndroid Build Coastguard Worker // scaling adjustments.
270*c8dee2aaSAndroid Build Coastguard Worker auto [view, ct] = skgpu::ganesh::AsView(rContext, image, skgpu::Mipmapped::kNo);
271*c8dee2aaSAndroid Build Coastguard Worker if (!view) {
272*c8dee2aaSAndroid Build Coastguard Worker return;
273*c8dee2aaSAndroid Build Coastguard Worker }
274*c8dee2aaSAndroid Build Coastguard Worker GrColorInfo info(image->imageInfo().colorInfo());
275*c8dee2aaSAndroid Build Coastguard Worker info = info.makeColorType(ct);
276*c8dee2aaSAndroid Build Coastguard Worker draw_texture(sdc,
277*c8dee2aaSAndroid Build Coastguard Worker clip,
278*c8dee2aaSAndroid Build Coastguard Worker localToDevice,
279*c8dee2aaSAndroid Build Coastguard Worker paint,
280*c8dee2aaSAndroid Build Coastguard Worker sampling.filter,
281*c8dee2aaSAndroid Build Coastguard Worker src,
282*c8dee2aaSAndroid Build Coastguard Worker dst,
283*c8dee2aaSAndroid Build Coastguard Worker dstClip,
284*c8dee2aaSAndroid Build Coastguard Worker aaFlags,
285*c8dee2aaSAndroid Build Coastguard Worker constraint,
286*c8dee2aaSAndroid Build Coastguard Worker std::move(view),
287*c8dee2aaSAndroid Build Coastguard Worker info);
288*c8dee2aaSAndroid Build Coastguard Worker return;
289*c8dee2aaSAndroid Build Coastguard Worker }
290*c8dee2aaSAndroid Build Coastguard Worker
291*c8dee2aaSAndroid Build Coastguard Worker const SkMaskFilter* mf = paint.getMaskFilter();
292*c8dee2aaSAndroid Build Coastguard Worker
293*c8dee2aaSAndroid Build Coastguard Worker // The shader expects proper local coords, so we can't replace local coords with texture coords
294*c8dee2aaSAndroid Build Coastguard Worker // if the shader will be used. If we have a mask filter we will change the underlying geometry
295*c8dee2aaSAndroid Build Coastguard Worker // that is rendered.
296*c8dee2aaSAndroid Build Coastguard Worker bool canUseTextureCoordsAsLocalCoords = !use_shader(image->isAlphaOnly(), paint) && !mf;
297*c8dee2aaSAndroid Build Coastguard Worker
298*c8dee2aaSAndroid Build Coastguard Worker // Specifying the texture coords as local coordinates is an attempt to enable more GrDrawOp
299*c8dee2aaSAndroid Build Coastguard Worker // combining by not baking anything about the srcRect, dstRect, or ctm, into the texture
300*c8dee2aaSAndroid Build Coastguard Worker // FP. In the future this should be an opaque optimization enabled by the combination of
301*c8dee2aaSAndroid Build Coastguard Worker // GrDrawOp/GP and FP.
302*c8dee2aaSAndroid Build Coastguard Worker if (GrFragmentProcessors::IsSupported(mf)) {
303*c8dee2aaSAndroid Build Coastguard Worker mf = nullptr;
304*c8dee2aaSAndroid Build Coastguard Worker }
305*c8dee2aaSAndroid Build Coastguard Worker
306*c8dee2aaSAndroid Build Coastguard Worker bool restrictToSubset = SkCanvas::kStrict_SrcRectConstraint == constraint;
307*c8dee2aaSAndroid Build Coastguard Worker
308*c8dee2aaSAndroid Build Coastguard Worker // If we have to outset for AA then we will generate texture coords outside the src rect. The
309*c8dee2aaSAndroid Build Coastguard Worker // same happens for any mask filter that extends the bounds rendered in the dst.
310*c8dee2aaSAndroid Build Coastguard Worker // This is conservative as a mask filter does not have to expand the bounds rendered.
311*c8dee2aaSAndroid Build Coastguard Worker bool coordsAllInsideSrcRect = aaFlags == GrQuadAAFlags::kNone && !mf;
312*c8dee2aaSAndroid Build Coastguard Worker
313*c8dee2aaSAndroid Build Coastguard Worker // Check for optimization to drop the src rect constraint when using linear filtering.
314*c8dee2aaSAndroid Build Coastguard Worker // TODO: Just rely on image to handle this.
315*c8dee2aaSAndroid Build Coastguard Worker if (sampling.isAniso() && !sampling.useCubic && sampling.filter == SkFilterMode::kLinear &&
316*c8dee2aaSAndroid Build Coastguard Worker restrictToSubset && sampling.mipmap == SkMipmapMode::kNone && coordsAllInsideSrcRect &&
317*c8dee2aaSAndroid Build Coastguard Worker !ib->isYUVA()) {
318*c8dee2aaSAndroid Build Coastguard Worker SkMatrix combinedMatrix;
319*c8dee2aaSAndroid Build Coastguard Worker combinedMatrix.setConcat(localToDevice, srcToDst);
320*c8dee2aaSAndroid Build Coastguard Worker if (can_ignore_linear_filtering_subset(src, combinedMatrix, sdc->numSamples())) {
321*c8dee2aaSAndroid Build Coastguard Worker restrictToSubset = false;
322*c8dee2aaSAndroid Build Coastguard Worker }
323*c8dee2aaSAndroid Build Coastguard Worker }
324*c8dee2aaSAndroid Build Coastguard Worker
325*c8dee2aaSAndroid Build Coastguard Worker SkMatrix textureMatrix;
326*c8dee2aaSAndroid Build Coastguard Worker if (canUseTextureCoordsAsLocalCoords) {
327*c8dee2aaSAndroid Build Coastguard Worker textureMatrix = SkMatrix::I();
328*c8dee2aaSAndroid Build Coastguard Worker } else {
329*c8dee2aaSAndroid Build Coastguard Worker if (!srcToDst.invert(&textureMatrix)) {
330*c8dee2aaSAndroid Build Coastguard Worker return;
331*c8dee2aaSAndroid Build Coastguard Worker }
332*c8dee2aaSAndroid Build Coastguard Worker }
333*c8dee2aaSAndroid Build Coastguard Worker const SkRect* subset = restrictToSubset ? &src : nullptr;
334*c8dee2aaSAndroid Build Coastguard Worker const SkRect* domain = coordsAllInsideSrcRect ? &src : nullptr;
335*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tileModes[] = {tm, tm};
336*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<GrFragmentProcessor> fp = skgpu::ganesh::AsFragmentProcessor(
337*c8dee2aaSAndroid Build Coastguard Worker rContext, image, sampling, tileModes, textureMatrix, subset, domain);
338*c8dee2aaSAndroid Build Coastguard Worker fp = GrColorSpaceXformEffect::Make(
339*c8dee2aaSAndroid Build Coastguard Worker std::move(fp), image->imageInfo().colorInfo(), sdc->colorInfo());
340*c8dee2aaSAndroid Build Coastguard Worker if (image->isAlphaOnly()) {
341*c8dee2aaSAndroid Build Coastguard Worker if (const auto* shader = as_SB(paint.getShader())) {
342*c8dee2aaSAndroid Build Coastguard Worker auto shaderFP = GrFragmentProcessors::Make(shader,
343*c8dee2aaSAndroid Build Coastguard Worker GrFPArgs(rContext,
344*c8dee2aaSAndroid Build Coastguard Worker &sdc->colorInfo(),
345*c8dee2aaSAndroid Build Coastguard Worker sdc->surfaceProps(),
346*c8dee2aaSAndroid Build Coastguard Worker GrFPArgs::Scope::kDefault),
347*c8dee2aaSAndroid Build Coastguard Worker localToDevice);
348*c8dee2aaSAndroid Build Coastguard Worker if (!shaderFP) {
349*c8dee2aaSAndroid Build Coastguard Worker return;
350*c8dee2aaSAndroid Build Coastguard Worker }
351*c8dee2aaSAndroid Build Coastguard Worker fp = GrBlendFragmentProcessor::Make<SkBlendMode::kDstIn>(std::move(fp),
352*c8dee2aaSAndroid Build Coastguard Worker std::move(shaderFP));
353*c8dee2aaSAndroid Build Coastguard Worker } else {
354*c8dee2aaSAndroid Build Coastguard Worker // Multiply the input (paint) color by the texture (alpha)
355*c8dee2aaSAndroid Build Coastguard Worker fp = GrFragmentProcessor::MulInputByChildAlpha(std::move(fp));
356*c8dee2aaSAndroid Build Coastguard Worker }
357*c8dee2aaSAndroid Build Coastguard Worker }
358*c8dee2aaSAndroid Build Coastguard Worker
359*c8dee2aaSAndroid Build Coastguard Worker GrPaint grPaint;
360*c8dee2aaSAndroid Build Coastguard Worker if (!SkPaintToGrPaintReplaceShader(rContext,
361*c8dee2aaSAndroid Build Coastguard Worker sdc->colorInfo(),
362*c8dee2aaSAndroid Build Coastguard Worker paint,
363*c8dee2aaSAndroid Build Coastguard Worker localToDevice,
364*c8dee2aaSAndroid Build Coastguard Worker std::move(fp),
365*c8dee2aaSAndroid Build Coastguard Worker sdc->surfaceProps(),
366*c8dee2aaSAndroid Build Coastguard Worker &grPaint)) {
367*c8dee2aaSAndroid Build Coastguard Worker return;
368*c8dee2aaSAndroid Build Coastguard Worker }
369*c8dee2aaSAndroid Build Coastguard Worker
370*c8dee2aaSAndroid Build Coastguard Worker if (!mf) {
371*c8dee2aaSAndroid Build Coastguard Worker // Can draw the image directly (any mask filter on the paint was converted to an FP already)
372*c8dee2aaSAndroid Build Coastguard Worker if (dstClip) {
373*c8dee2aaSAndroid Build Coastguard Worker SkPoint srcClipPoints[4];
374*c8dee2aaSAndroid Build Coastguard Worker SkPoint* srcClip = nullptr;
375*c8dee2aaSAndroid Build Coastguard Worker if (canUseTextureCoordsAsLocalCoords) {
376*c8dee2aaSAndroid Build Coastguard Worker // Calculate texture coordinates that match the dst clip
377*c8dee2aaSAndroid Build Coastguard Worker GrMapRectPoints(dst, src, dstClip, srcClipPoints, 4);
378*c8dee2aaSAndroid Build Coastguard Worker srcClip = srcClipPoints;
379*c8dee2aaSAndroid Build Coastguard Worker }
380*c8dee2aaSAndroid Build Coastguard Worker sdc->fillQuadWithEdgeAA(clip, std::move(grPaint), aaFlags, localToDevice,
381*c8dee2aaSAndroid Build Coastguard Worker dstClip, srcClip);
382*c8dee2aaSAndroid Build Coastguard Worker } else {
383*c8dee2aaSAndroid Build Coastguard Worker // Provide explicit texture coords when possible, otherwise rely on texture matrix
384*c8dee2aaSAndroid Build Coastguard Worker sdc->fillRectWithEdgeAA(clip, std::move(grPaint), aaFlags, localToDevice, dst,
385*c8dee2aaSAndroid Build Coastguard Worker canUseTextureCoordsAsLocalCoords ? &src : nullptr);
386*c8dee2aaSAndroid Build Coastguard Worker }
387*c8dee2aaSAndroid Build Coastguard Worker } else {
388*c8dee2aaSAndroid Build Coastguard Worker // Must draw the mask filter as a GrStyledShape. For now, this loses the per-edge AA
389*c8dee2aaSAndroid Build Coastguard Worker // information since it always draws with AA, but that should not be noticeable since the
390*c8dee2aaSAndroid Build Coastguard Worker // mask filter is probably a blur.
391*c8dee2aaSAndroid Build Coastguard Worker GrStyledShape shape;
392*c8dee2aaSAndroid Build Coastguard Worker if (dstClip) {
393*c8dee2aaSAndroid Build Coastguard Worker // Represent it as an SkPath formed from the dstClip
394*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
395*c8dee2aaSAndroid Build Coastguard Worker path.addPoly(dstClip, 4, true);
396*c8dee2aaSAndroid Build Coastguard Worker shape = GrStyledShape(path);
397*c8dee2aaSAndroid Build Coastguard Worker } else {
398*c8dee2aaSAndroid Build Coastguard Worker shape = GrStyledShape(dst);
399*c8dee2aaSAndroid Build Coastguard Worker }
400*c8dee2aaSAndroid Build Coastguard Worker
401*c8dee2aaSAndroid Build Coastguard Worker GrBlurUtils::DrawShapeWithMaskFilter(
402*c8dee2aaSAndroid Build Coastguard Worker rContext, sdc, clip, shape, std::move(grPaint), localToDevice, mf);
403*c8dee2aaSAndroid Build Coastguard Worker }
404*c8dee2aaSAndroid Build Coastguard Worker }
405*c8dee2aaSAndroid Build Coastguard Worker
drawSpecial(SkSpecialImage * special,const SkMatrix & localToDevice,const SkSamplingOptions & origSampling,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)406*c8dee2aaSAndroid Build Coastguard Worker void Device::drawSpecial(SkSpecialImage* special,
407*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& localToDevice,
408*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions& origSampling,
409*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
410*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::SrcRectConstraint constraint) {
411*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!paint.getMaskFilter() && !paint.getImageFilter());
412*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(special->isGaneshBacked());
413*c8dee2aaSAndroid Build Coastguard Worker
414*c8dee2aaSAndroid Build Coastguard Worker SkRect src = SkRect::Make(special->subset());
415*c8dee2aaSAndroid Build Coastguard Worker SkRect dst = SkRect::MakeWH(special->width(), special->height());
416*c8dee2aaSAndroid Build Coastguard Worker SkMatrix srcToDst = SkMatrix::RectToRect(src, dst);
417*c8dee2aaSAndroid Build Coastguard Worker
418*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions sampling = SkSamplingOptions(downgrade_to_filter(origSampling));
419*c8dee2aaSAndroid Build Coastguard Worker GrAA aa = fSurfaceDrawContext->chooseAA(paint);
420*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::QuadAAFlags aaFlags = (aa == GrAA::kYes) ? SkCanvas::kAll_QuadAAFlags
421*c8dee2aaSAndroid Build Coastguard Worker : SkCanvas::kNone_QuadAAFlags;
422*c8dee2aaSAndroid Build Coastguard Worker
423*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxyView view = SkSpecialImages::AsView(this->recordingContext(), special);
424*c8dee2aaSAndroid Build Coastguard Worker if (!view) {
425*c8dee2aaSAndroid Build Coastguard Worker // This shouldn't happen since we shouldn't be mixing SkSpecialImage subclasses but
426*c8dee2aaSAndroid Build Coastguard Worker // returning early should avoid problems in release builds.
427*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(false);
428*c8dee2aaSAndroid Build Coastguard Worker return;
429*c8dee2aaSAndroid Build Coastguard Worker }
430*c8dee2aaSAndroid Build Coastguard Worker
431*c8dee2aaSAndroid Build Coastguard Worker if (constraint == SkCanvas::kFast_SrcRectConstraint) {
432*c8dee2aaSAndroid Build Coastguard Worker // If 'fast' was requested, we assume the caller has done sufficient analysis to know the
433*c8dee2aaSAndroid Build Coastguard Worker // logical dimensions are safe (which is true for FilterResult, the only current caller that
434*c8dee2aaSAndroid Build Coastguard Worker // passes in 'fast'). Without exactify'ing the proxy, GrTextureEffect would re-introduce
435*c8dee2aaSAndroid Build Coastguard Worker // subset clamping.
436*c8dee2aaSAndroid Build Coastguard Worker view.proxy()->priv().exactify();
437*c8dee2aaSAndroid Build Coastguard Worker }
438*c8dee2aaSAndroid Build Coastguard Worker
439*c8dee2aaSAndroid Build Coastguard Worker SkImage_Ganesh image(sk_ref_sp(special->getContext()),
440*c8dee2aaSAndroid Build Coastguard Worker special->uniqueID(),
441*c8dee2aaSAndroid Build Coastguard Worker std::move(view),
442*c8dee2aaSAndroid Build Coastguard Worker special->colorInfo());
443*c8dee2aaSAndroid Build Coastguard Worker // In most cases this ought to hit draw_texture since there won't be a color filter,
444*c8dee2aaSAndroid Build Coastguard Worker // alpha-only texture+shader, or a high filter quality.
445*c8dee2aaSAndroid Build Coastguard Worker this->drawEdgeAAImage(&image,
446*c8dee2aaSAndroid Build Coastguard Worker src,
447*c8dee2aaSAndroid Build Coastguard Worker dst,
448*c8dee2aaSAndroid Build Coastguard Worker /* dstClip= */nullptr,
449*c8dee2aaSAndroid Build Coastguard Worker aaFlags,
450*c8dee2aaSAndroid Build Coastguard Worker localToDevice,
451*c8dee2aaSAndroid Build Coastguard Worker sampling,
452*c8dee2aaSAndroid Build Coastguard Worker paint,
453*c8dee2aaSAndroid Build Coastguard Worker constraint,
454*c8dee2aaSAndroid Build Coastguard Worker srcToDst,
455*c8dee2aaSAndroid Build Coastguard Worker SkTileMode::kClamp);
456*c8dee2aaSAndroid Build Coastguard Worker }
457*c8dee2aaSAndroid Build Coastguard Worker
drawImageQuadDirect(const SkImage * image,const SkRect & srcRect,const SkRect & dstRect,const SkPoint dstClip[4],SkCanvas::QuadAAFlags aaFlags,const SkMatrix * preViewMatrix,const SkSamplingOptions & origSampling,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)458*c8dee2aaSAndroid Build Coastguard Worker void Device::drawImageQuadDirect(const SkImage* image,
459*c8dee2aaSAndroid Build Coastguard Worker const SkRect& srcRect,
460*c8dee2aaSAndroid Build Coastguard Worker const SkRect& dstRect,
461*c8dee2aaSAndroid Build Coastguard Worker const SkPoint dstClip[4],
462*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::QuadAAFlags aaFlags,
463*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix* preViewMatrix,
464*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions& origSampling,
465*c8dee2aaSAndroid Build Coastguard Worker const SkPaint& paint,
466*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::SrcRectConstraint constraint) {
467*c8dee2aaSAndroid Build Coastguard Worker SkRect src;
468*c8dee2aaSAndroid Build Coastguard Worker SkRect dst;
469*c8dee2aaSAndroid Build Coastguard Worker SkMatrix srcToDst;
470*c8dee2aaSAndroid Build Coastguard Worker auto mode = TiledTextureUtils::OptimizeSampleArea(SkISize::Make(image->width(),
471*c8dee2aaSAndroid Build Coastguard Worker image->height()),
472*c8dee2aaSAndroid Build Coastguard Worker srcRect, dstRect, dstClip,
473*c8dee2aaSAndroid Build Coastguard Worker &src, &dst, &srcToDst);
474*c8dee2aaSAndroid Build Coastguard Worker if (mode == TiledTextureUtils::ImageDrawMode::kSkip) {
475*c8dee2aaSAndroid Build Coastguard Worker return;
476*c8dee2aaSAndroid Build Coastguard Worker }
477*c8dee2aaSAndroid Build Coastguard Worker
478*c8dee2aaSAndroid Build Coastguard Worker if (src.contains(image->bounds())) {
479*c8dee2aaSAndroid Build Coastguard Worker constraint = SkCanvas::kFast_SrcRectConstraint;
480*c8dee2aaSAndroid Build Coastguard Worker }
481*c8dee2aaSAndroid Build Coastguard Worker // Depending on the nature of image, it can flow through more or less optimal pipelines
482*c8dee2aaSAndroid Build Coastguard Worker SkTileMode tileMode = mode == TiledTextureUtils::ImageDrawMode::kDecal ? SkTileMode::kDecal
483*c8dee2aaSAndroid Build Coastguard Worker : SkTileMode::kClamp;
484*c8dee2aaSAndroid Build Coastguard Worker
485*c8dee2aaSAndroid Build Coastguard Worker // Get final CTM matrix
486*c8dee2aaSAndroid Build Coastguard Worker SkMatrix ctm = this->localToDevice();
487*c8dee2aaSAndroid Build Coastguard Worker if (preViewMatrix) {
488*c8dee2aaSAndroid Build Coastguard Worker ctm.preConcat(*preViewMatrix);
489*c8dee2aaSAndroid Build Coastguard Worker }
490*c8dee2aaSAndroid Build Coastguard Worker
491*c8dee2aaSAndroid Build Coastguard Worker SkSamplingOptions sampling = origSampling;
492*c8dee2aaSAndroid Build Coastguard Worker bool sharpenMM = fContext->priv().options().fSharpenMipmappedTextures;
493*c8dee2aaSAndroid Build Coastguard Worker if (sampling.mipmap != SkMipmapMode::kNone &&
494*c8dee2aaSAndroid Build Coastguard Worker TiledTextureUtils::CanDisableMipmap(ctm, srcToDst, sharpenMM)) {
495*c8dee2aaSAndroid Build Coastguard Worker sampling = SkSamplingOptions(sampling.filter);
496*c8dee2aaSAndroid Build Coastguard Worker }
497*c8dee2aaSAndroid Build Coastguard Worker
498*c8dee2aaSAndroid Build Coastguard Worker this->drawEdgeAAImage(image,
499*c8dee2aaSAndroid Build Coastguard Worker src,
500*c8dee2aaSAndroid Build Coastguard Worker dst,
501*c8dee2aaSAndroid Build Coastguard Worker dstClip,
502*c8dee2aaSAndroid Build Coastguard Worker aaFlags,
503*c8dee2aaSAndroid Build Coastguard Worker ctm,
504*c8dee2aaSAndroid Build Coastguard Worker sampling,
505*c8dee2aaSAndroid Build Coastguard Worker paint,
506*c8dee2aaSAndroid Build Coastguard Worker constraint,
507*c8dee2aaSAndroid Build Coastguard Worker srcToDst,
508*c8dee2aaSAndroid Build Coastguard Worker tileMode);
509*c8dee2aaSAndroid Build Coastguard Worker }
510*c8dee2aaSAndroid Build Coastguard Worker
drawEdgeAAImageSet(const SkCanvas::ImageSetEntry set[],int count,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkSamplingOptions & sampling,const SkPaint & paint,SkCanvas::SrcRectConstraint constraint)511*c8dee2aaSAndroid Build Coastguard Worker void Device::drawEdgeAAImageSet(const SkCanvas::ImageSetEntry set[], int count,
512*c8dee2aaSAndroid Build Coastguard Worker const SkPoint dstClips[], const SkMatrix preViewMatrices[],
513*c8dee2aaSAndroid Build Coastguard Worker const SkSamplingOptions& sampling, const SkPaint& paint,
514*c8dee2aaSAndroid Build Coastguard Worker SkCanvas::SrcRectConstraint constraint) {
515*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(count > 0);
516*c8dee2aaSAndroid Build Coastguard Worker if (!can_use_draw_texture(paint, sampling)) {
517*c8dee2aaSAndroid Build Coastguard Worker // Send every entry through drawImageQuad() to handle the more complicated paint
518*c8dee2aaSAndroid Build Coastguard Worker int dstClipIndex = 0;
519*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < count; ++i) {
520*c8dee2aaSAndroid Build Coastguard Worker // Only no clip or quad clip are supported
521*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!set[i].fHasClip || dstClips);
522*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(set[i].fMatrixIndex < 0 || preViewMatrices);
523*c8dee2aaSAndroid Build Coastguard Worker
524*c8dee2aaSAndroid Build Coastguard Worker SkTCopyOnFirstWrite<SkPaint> entryPaint(paint);
525*c8dee2aaSAndroid Build Coastguard Worker if (set[i].fAlpha != 1.f) {
526*c8dee2aaSAndroid Build Coastguard Worker auto paintAlpha = paint.getAlphaf();
527*c8dee2aaSAndroid Build Coastguard Worker entryPaint.writable()->setAlphaf(paintAlpha * set[i].fAlpha);
528*c8dee2aaSAndroid Build Coastguard Worker }
529*c8dee2aaSAndroid Build Coastguard Worker this->drawImageQuadDirect(
530*c8dee2aaSAndroid Build Coastguard Worker set[i].fImage.get(), set[i].fSrcRect, set[i].fDstRect,
531*c8dee2aaSAndroid Build Coastguard Worker set[i].fHasClip ? dstClips + dstClipIndex : nullptr,
532*c8dee2aaSAndroid Build Coastguard Worker static_cast<SkCanvas::QuadAAFlags>(set[i].fAAFlags),
533*c8dee2aaSAndroid Build Coastguard Worker set[i].fMatrixIndex < 0 ? nullptr : preViewMatrices + set[i].fMatrixIndex,
534*c8dee2aaSAndroid Build Coastguard Worker sampling, *entryPaint, constraint);
535*c8dee2aaSAndroid Build Coastguard Worker dstClipIndex += 4 * set[i].fHasClip;
536*c8dee2aaSAndroid Build Coastguard Worker }
537*c8dee2aaSAndroid Build Coastguard Worker return;
538*c8dee2aaSAndroid Build Coastguard Worker }
539*c8dee2aaSAndroid Build Coastguard Worker
540*c8dee2aaSAndroid Build Coastguard Worker GrSamplerState::Filter filter = sampling.filter == SkFilterMode::kNearest
541*c8dee2aaSAndroid Build Coastguard Worker ? GrSamplerState::Filter::kNearest
542*c8dee2aaSAndroid Build Coastguard Worker : GrSamplerState::Filter::kLinear;
543*c8dee2aaSAndroid Build Coastguard Worker SkBlendMode mode = paint.getBlendMode_or(SkBlendMode::kSrcOver);
544*c8dee2aaSAndroid Build Coastguard Worker
545*c8dee2aaSAndroid Build Coastguard Worker AutoTArray<GrTextureSetEntry> textures(count);
546*c8dee2aaSAndroid Build Coastguard Worker // We accumulate compatible proxies until we find an an incompatible one or reach the end and
547*c8dee2aaSAndroid Build Coastguard Worker // issue the accumulated 'n' draws starting at 'base'. 'p' represents the number of proxy
548*c8dee2aaSAndroid Build Coastguard Worker // switches that occur within the 'n' entries.
549*c8dee2aaSAndroid Build Coastguard Worker int base = 0, n = 0, p = 0;
550*c8dee2aaSAndroid Build Coastguard Worker auto draw = [&](int nextBase) {
551*c8dee2aaSAndroid Build Coastguard Worker if (n > 0) {
552*c8dee2aaSAndroid Build Coastguard Worker auto textureXform = GrColorSpaceXform::Make(set[base].fImage->imageInfo().colorInfo(),
553*c8dee2aaSAndroid Build Coastguard Worker fSurfaceDrawContext->colorInfo());
554*c8dee2aaSAndroid Build Coastguard Worker fSurfaceDrawContext->drawTextureSet(this->clip(),
555*c8dee2aaSAndroid Build Coastguard Worker textures.get() + base,
556*c8dee2aaSAndroid Build Coastguard Worker n,
557*c8dee2aaSAndroid Build Coastguard Worker p,
558*c8dee2aaSAndroid Build Coastguard Worker filter,
559*c8dee2aaSAndroid Build Coastguard Worker GrSamplerState::MipmapMode::kNone,
560*c8dee2aaSAndroid Build Coastguard Worker mode,
561*c8dee2aaSAndroid Build Coastguard Worker constraint,
562*c8dee2aaSAndroid Build Coastguard Worker this->localToDevice(),
563*c8dee2aaSAndroid Build Coastguard Worker std::move(textureXform));
564*c8dee2aaSAndroid Build Coastguard Worker }
565*c8dee2aaSAndroid Build Coastguard Worker base = nextBase;
566*c8dee2aaSAndroid Build Coastguard Worker n = 0;
567*c8dee2aaSAndroid Build Coastguard Worker p = 0;
568*c8dee2aaSAndroid Build Coastguard Worker };
569*c8dee2aaSAndroid Build Coastguard Worker int dstClipIndex = 0;
570*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < count; ++i) {
571*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!set[i].fHasClip || dstClips);
572*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(set[i].fMatrixIndex < 0 || preViewMatrices);
573*c8dee2aaSAndroid Build Coastguard Worker
574*c8dee2aaSAndroid Build Coastguard Worker // Manage the dst clip pointer tracking before any continues are used so we don't lose
575*c8dee2aaSAndroid Build Coastguard Worker // our place in the dstClips array.
576*c8dee2aaSAndroid Build Coastguard Worker const SkPoint* clip = set[i].fHasClip ? dstClips + dstClipIndex : nullptr;
577*c8dee2aaSAndroid Build Coastguard Worker dstClipIndex += 4 * set[i].fHasClip;
578*c8dee2aaSAndroid Build Coastguard Worker
579*c8dee2aaSAndroid Build Coastguard Worker // The default SkDevice implementation is based on drawImageRect which does not allow
580*c8dee2aaSAndroid Build Coastguard Worker // non-sorted src rects. TODO: Decide this is OK or make sure we handle it.
581*c8dee2aaSAndroid Build Coastguard Worker if (!set[i].fSrcRect.isSorted()) {
582*c8dee2aaSAndroid Build Coastguard Worker draw(i + 1);
583*c8dee2aaSAndroid Build Coastguard Worker continue;
584*c8dee2aaSAndroid Build Coastguard Worker }
585*c8dee2aaSAndroid Build Coastguard Worker
586*c8dee2aaSAndroid Build Coastguard Worker GrSurfaceProxyView view;
587*c8dee2aaSAndroid Build Coastguard Worker const SkImage_Base* image = as_IB(set[i].fImage.get());
588*c8dee2aaSAndroid Build Coastguard Worker // Extract view from image, but skip YUV images so they get processed through
589*c8dee2aaSAndroid Build Coastguard Worker // drawImageQuad and the proper effect to dynamically sample their planes.
590*c8dee2aaSAndroid Build Coastguard Worker if (!image->isYUVA()) {
591*c8dee2aaSAndroid Build Coastguard Worker std::tie(view, std::ignore) =
592*c8dee2aaSAndroid Build Coastguard Worker skgpu::ganesh::AsView(this->recordingContext(), image, skgpu::Mipmapped::kNo);
593*c8dee2aaSAndroid Build Coastguard Worker if (image->isAlphaOnly()) {
594*c8dee2aaSAndroid Build Coastguard Worker skgpu::Swizzle swizzle = skgpu::Swizzle::Concat(view.swizzle(),
595*c8dee2aaSAndroid Build Coastguard Worker skgpu::Swizzle("aaaa"));
596*c8dee2aaSAndroid Build Coastguard Worker view = {view.detachProxy(), view.origin(), swizzle};
597*c8dee2aaSAndroid Build Coastguard Worker }
598*c8dee2aaSAndroid Build Coastguard Worker }
599*c8dee2aaSAndroid Build Coastguard Worker
600*c8dee2aaSAndroid Build Coastguard Worker if (!view) {
601*c8dee2aaSAndroid Build Coastguard Worker // This image can't go through the texture op, send through general image pipeline
602*c8dee2aaSAndroid Build Coastguard Worker // after flushing current batch.
603*c8dee2aaSAndroid Build Coastguard Worker draw(i + 1);
604*c8dee2aaSAndroid Build Coastguard Worker SkTCopyOnFirstWrite<SkPaint> entryPaint(paint);
605*c8dee2aaSAndroid Build Coastguard Worker if (set[i].fAlpha != 1.f) {
606*c8dee2aaSAndroid Build Coastguard Worker auto paintAlpha = paint.getAlphaf();
607*c8dee2aaSAndroid Build Coastguard Worker entryPaint.writable()->setAlphaf(paintAlpha * set[i].fAlpha);
608*c8dee2aaSAndroid Build Coastguard Worker }
609*c8dee2aaSAndroid Build Coastguard Worker this->drawImageQuadDirect(
610*c8dee2aaSAndroid Build Coastguard Worker image, set[i].fSrcRect, set[i].fDstRect, clip,
611*c8dee2aaSAndroid Build Coastguard Worker static_cast<SkCanvas::QuadAAFlags>(set[i].fAAFlags),
612*c8dee2aaSAndroid Build Coastguard Worker set[i].fMatrixIndex < 0 ? nullptr : preViewMatrices + set[i].fMatrixIndex,
613*c8dee2aaSAndroid Build Coastguard Worker sampling, *entryPaint, constraint);
614*c8dee2aaSAndroid Build Coastguard Worker continue;
615*c8dee2aaSAndroid Build Coastguard Worker }
616*c8dee2aaSAndroid Build Coastguard Worker
617*c8dee2aaSAndroid Build Coastguard Worker textures[i].fProxyView = std::move(view);
618*c8dee2aaSAndroid Build Coastguard Worker textures[i].fSrcAlphaType = image->alphaType();
619*c8dee2aaSAndroid Build Coastguard Worker textures[i].fSrcRect = set[i].fSrcRect;
620*c8dee2aaSAndroid Build Coastguard Worker textures[i].fDstRect = set[i].fDstRect;
621*c8dee2aaSAndroid Build Coastguard Worker textures[i].fDstClipQuad = clip;
622*c8dee2aaSAndroid Build Coastguard Worker textures[i].fPreViewMatrix =
623*c8dee2aaSAndroid Build Coastguard Worker set[i].fMatrixIndex < 0 ? nullptr : preViewMatrices + set[i].fMatrixIndex;
624*c8dee2aaSAndroid Build Coastguard Worker textures[i].fColor = texture_color(paint.getColor4f(), set[i].fAlpha,
625*c8dee2aaSAndroid Build Coastguard Worker SkColorTypeToGrColorType(image->colorType()),
626*c8dee2aaSAndroid Build Coastguard Worker fSurfaceDrawContext->colorInfo());
627*c8dee2aaSAndroid Build Coastguard Worker textures[i].fAAFlags = SkToGrQuadAAFlags(set[i].fAAFlags);
628*c8dee2aaSAndroid Build Coastguard Worker
629*c8dee2aaSAndroid Build Coastguard Worker if (n > 0 &&
630*c8dee2aaSAndroid Build Coastguard Worker (!GrTextureProxy::ProxiesAreCompatibleAsDynamicState(
631*c8dee2aaSAndroid Build Coastguard Worker textures[i].fProxyView.proxy(),
632*c8dee2aaSAndroid Build Coastguard Worker textures[base].fProxyView.proxy()) ||
633*c8dee2aaSAndroid Build Coastguard Worker textures[i].fProxyView.swizzle() != textures[base].fProxyView.swizzle() ||
634*c8dee2aaSAndroid Build Coastguard Worker set[i].fImage->alphaType() != set[base].fImage->alphaType() ||
635*c8dee2aaSAndroid Build Coastguard Worker !SkColorSpace::Equals(set[i].fImage->colorSpace(), set[base].fImage->colorSpace()))) {
636*c8dee2aaSAndroid Build Coastguard Worker draw(i);
637*c8dee2aaSAndroid Build Coastguard Worker }
638*c8dee2aaSAndroid Build Coastguard Worker // Whether or not we submitted a draw in the above if(), this ith entry is in the current
639*c8dee2aaSAndroid Build Coastguard Worker // set being accumulated so increment n, and increment p if proxies are different.
640*c8dee2aaSAndroid Build Coastguard Worker ++n;
641*c8dee2aaSAndroid Build Coastguard Worker if (n == 1 || textures[i - 1].fProxyView.proxy() != textures[i].fProxyView.proxy()) {
642*c8dee2aaSAndroid Build Coastguard Worker // First proxy or a different proxy (that is compatible, otherwise we'd have drawn up
643*c8dee2aaSAndroid Build Coastguard Worker // to i - 1).
644*c8dee2aaSAndroid Build Coastguard Worker ++p;
645*c8dee2aaSAndroid Build Coastguard Worker }
646*c8dee2aaSAndroid Build Coastguard Worker }
647*c8dee2aaSAndroid Build Coastguard Worker draw(count);
648*c8dee2aaSAndroid Build Coastguard Worker }
649*c8dee2aaSAndroid Build Coastguard Worker
650*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::ganesh
651