1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2015 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/v1/Device_v1.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h"
11cb93a386Sopenharmony_ci#include "include/gpu/GrRecordingContext.h"
12cb93a386Sopenharmony_ci#include "include/private/SkTPin.h"
13cb93a386Sopenharmony_ci#include "src/core/SkDraw.h"
14cb93a386Sopenharmony_ci#include "src/core/SkImagePriv.h"
15cb93a386Sopenharmony_ci#include "src/core/SkMaskFilterBase.h"
16cb93a386Sopenharmony_ci#include "src/core/SkSpecialImage.h"
17cb93a386Sopenharmony_ci#include "src/gpu/GrBlurUtils.h"
18cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h"
19cb93a386Sopenharmony_ci#include "src/gpu/GrColorSpaceXform.h"
20cb93a386Sopenharmony_ci#include "src/gpu/GrOpsTypes.h"
21cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h"
22cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h"
23cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h"
24cb93a386Sopenharmony_ci#include "src/gpu/effects/GrBicubicEffect.h"
25cb93a386Sopenharmony_ci#include "src/gpu/effects/GrBlendFragmentProcessor.h"
26cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h"
27cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrRect.h"
28cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h"
29cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h"
30cb93a386Sopenharmony_ci#include "src/image/SkImage_Base.h"
31cb93a386Sopenharmony_ci#include "src/image/SkImage_Gpu.h"
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_cinamespace {
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ciinline bool use_shader(bool textureIsAlphaOnly, const SkPaint& paint) {
36cb93a386Sopenharmony_ci    return textureIsAlphaOnly && paint.getShader();
37cb93a386Sopenharmony_ci}
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
40cb93a386Sopenharmony_ci//  Helper functions for dropping src rect subset with GrSamplerState::Filter::kLinear.
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_cistatic const SkScalar kColorBleedTolerance = 0.001f;
43cb93a386Sopenharmony_ci
44cb93a386Sopenharmony_cibool has_aligned_samples(const SkRect& srcRect, const SkRect& transformedRect) {
45cb93a386Sopenharmony_ci    // detect pixel disalignment
46cb93a386Sopenharmony_ci    if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) - transformedRect.left()) < kColorBleedTolerance &&
47cb93a386Sopenharmony_ci        SkScalarAbs(SkScalarRoundToScalar(transformedRect.top())  - transformedRect.top())  < kColorBleedTolerance &&
48cb93a386Sopenharmony_ci        SkScalarAbs(transformedRect.width()  - srcRect.width())  < kColorBleedTolerance &&
49cb93a386Sopenharmony_ci        SkScalarAbs(transformedRect.height() - srcRect.height()) < kColorBleedTolerance) {
50cb93a386Sopenharmony_ci        return true;
51cb93a386Sopenharmony_ci    }
52cb93a386Sopenharmony_ci    return false;
53cb93a386Sopenharmony_ci}
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_cibool may_color_bleed(const SkRect& srcRect,
56cb93a386Sopenharmony_ci                     const SkRect& transformedRect,
57cb93a386Sopenharmony_ci                     const SkMatrix& m,
58cb93a386Sopenharmony_ci                     int numSamples) {
59cb93a386Sopenharmony_ci    // Only gets called if has_aligned_samples returned false.
60cb93a386Sopenharmony_ci    // So we can assume that sampling is axis aligned but not texel aligned.
61cb93a386Sopenharmony_ci    SkASSERT(!has_aligned_samples(srcRect, transformedRect));
62cb93a386Sopenharmony_ci    SkRect innerSrcRect(srcRect), innerTransformedRect, outerTransformedRect(transformedRect);
63cb93a386Sopenharmony_ci    if (numSamples > 1) {
64cb93a386Sopenharmony_ci        innerSrcRect.inset(SK_Scalar1, SK_Scalar1);
65cb93a386Sopenharmony_ci    } else {
66cb93a386Sopenharmony_ci        innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf);
67cb93a386Sopenharmony_ci    }
68cb93a386Sopenharmony_ci    m.mapRect(&innerTransformedRect, innerSrcRect);
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci    // The gap between outerTransformedRect and innerTransformedRect
71cb93a386Sopenharmony_ci    // represents the projection of the source border area, which is
72cb93a386Sopenharmony_ci    // problematic for color bleeding.  We must check whether any
73cb93a386Sopenharmony_ci    // destination pixels sample the border area.
74cb93a386Sopenharmony_ci    outerTransformedRect.inset(kColorBleedTolerance, kColorBleedTolerance);
75cb93a386Sopenharmony_ci    innerTransformedRect.outset(kColorBleedTolerance, kColorBleedTolerance);
76cb93a386Sopenharmony_ci    SkIRect outer, inner;
77cb93a386Sopenharmony_ci    outerTransformedRect.round(&outer);
78cb93a386Sopenharmony_ci    innerTransformedRect.round(&inner);
79cb93a386Sopenharmony_ci    // If the inner and outer rects round to the same result, it means the
80cb93a386Sopenharmony_ci    // border does not overlap any pixel centers. Yay!
81cb93a386Sopenharmony_ci    return inner != outer;
82cb93a386Sopenharmony_ci}
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_cibool can_ignore_linear_filtering_subset(const SkRect& srcSubset,
85cb93a386Sopenharmony_ci                                        const SkMatrix& srcRectToDeviceSpace,
86cb93a386Sopenharmony_ci                                        int numSamples) {
87cb93a386Sopenharmony_ci    if (srcRectToDeviceSpace.rectStaysRect()) {
88cb93a386Sopenharmony_ci        // sampling is axis-aligned
89cb93a386Sopenharmony_ci        SkRect transformedRect;
90cb93a386Sopenharmony_ci        srcRectToDeviceSpace.mapRect(&transformedRect, srcSubset);
91cb93a386Sopenharmony_ci
92cb93a386Sopenharmony_ci        if (has_aligned_samples(srcSubset, transformedRect) ||
93cb93a386Sopenharmony_ci            !may_color_bleed(srcSubset, transformedRect, srcRectToDeviceSpace, numSamples)) {
94cb93a386Sopenharmony_ci            return true;
95cb93a386Sopenharmony_ci        }
96cb93a386Sopenharmony_ci    }
97cb93a386Sopenharmony_ci    return false;
98cb93a386Sopenharmony_ci}
99cb93a386Sopenharmony_ci
100cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
101cb93a386Sopenharmony_ci//  Helper functions for tiling a large SkBitmap
102cb93a386Sopenharmony_ci
103cb93a386Sopenharmony_cistatic const int kBmpSmallTileSize = 1 << 10;
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ciinline int get_tile_count(const SkIRect& srcRect, int tileSize)  {
106cb93a386Sopenharmony_ci    int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1;
107cb93a386Sopenharmony_ci    int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1;
108cb93a386Sopenharmony_ci    return tilesX * tilesY;
109cb93a386Sopenharmony_ci}
110cb93a386Sopenharmony_ci
111cb93a386Sopenharmony_ciint determine_tile_size(const SkIRect& src, int maxTileSize) {
112cb93a386Sopenharmony_ci    if (maxTileSize <= kBmpSmallTileSize) {
113cb93a386Sopenharmony_ci        return maxTileSize;
114cb93a386Sopenharmony_ci    }
115cb93a386Sopenharmony_ci
116cb93a386Sopenharmony_ci    size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize);
117cb93a386Sopenharmony_ci    size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize);
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci    maxTileTotalTileSize *= maxTileSize * maxTileSize;
120cb93a386Sopenharmony_ci    smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize;
121cb93a386Sopenharmony_ci
122cb93a386Sopenharmony_ci    if (maxTileTotalTileSize > 2 * smallTotalTileSize) {
123cb93a386Sopenharmony_ci        return kBmpSmallTileSize;
124cb93a386Sopenharmony_ci    } else {
125cb93a386Sopenharmony_ci        return maxTileSize;
126cb93a386Sopenharmony_ci    }
127cb93a386Sopenharmony_ci}
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci// Given a bitmap, an optional src rect, and a context with a clip and matrix determine what
130cb93a386Sopenharmony_ci// pixels from the bitmap are necessary.
131cb93a386Sopenharmony_ciSkIRect determine_clipped_src_rect(int width, int height,
132cb93a386Sopenharmony_ci                                   const GrClip* clip,
133cb93a386Sopenharmony_ci                                   const SkMatrix& viewMatrix,
134cb93a386Sopenharmony_ci                                   const SkMatrix& srcToDstRect,
135cb93a386Sopenharmony_ci                                   const SkISize& imageDimensions,
136cb93a386Sopenharmony_ci                                   const SkRect* srcRectPtr) {
137cb93a386Sopenharmony_ci    SkIRect clippedSrcIRect = clip ? clip->getConservativeBounds()
138cb93a386Sopenharmony_ci                                   : SkIRect::MakeWH(width, height);
139cb93a386Sopenharmony_ci    SkMatrix inv = SkMatrix::Concat(viewMatrix, srcToDstRect);
140cb93a386Sopenharmony_ci    if (!inv.invert(&inv)) {
141cb93a386Sopenharmony_ci        return SkIRect::MakeEmpty();
142cb93a386Sopenharmony_ci    }
143cb93a386Sopenharmony_ci    SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
144cb93a386Sopenharmony_ci    inv.mapRect(&clippedSrcRect);
145cb93a386Sopenharmony_ci    if (srcRectPtr) {
146cb93a386Sopenharmony_ci        if (!clippedSrcRect.intersect(*srcRectPtr)) {
147cb93a386Sopenharmony_ci            return SkIRect::MakeEmpty();
148cb93a386Sopenharmony_ci        }
149cb93a386Sopenharmony_ci    }
150cb93a386Sopenharmony_ci    clippedSrcRect.roundOut(&clippedSrcIRect);
151cb93a386Sopenharmony_ci    SkIRect bmpBounds = SkIRect::MakeSize(imageDimensions);
152cb93a386Sopenharmony_ci    if (!clippedSrcIRect.intersect(bmpBounds)) {
153cb93a386Sopenharmony_ci        return SkIRect::MakeEmpty();
154cb93a386Sopenharmony_ci    }
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci    return clippedSrcIRect;
157cb93a386Sopenharmony_ci}
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci// tileSize and clippedSubset are valid if true is returned
160cb93a386Sopenharmony_cibool should_tile_image_id(GrRecordingContext* context,
161cb93a386Sopenharmony_ci                          SkISize rtSize,
162cb93a386Sopenharmony_ci                          const GrClip* clip,
163cb93a386Sopenharmony_ci                          uint32_t imageID,
164cb93a386Sopenharmony_ci                          const SkISize& imageSize,
165cb93a386Sopenharmony_ci                          const SkMatrix& ctm,
166cb93a386Sopenharmony_ci                          const SkMatrix& srcToDst,
167cb93a386Sopenharmony_ci                          const SkRect* src,
168cb93a386Sopenharmony_ci                          int maxTileSize,
169cb93a386Sopenharmony_ci                          int* tileSize,
170cb93a386Sopenharmony_ci                          SkIRect* clippedSubset) {
171cb93a386Sopenharmony_ci    // if it's larger than the max tile size, then we have no choice but tiling.
172cb93a386Sopenharmony_ci    if (imageSize.width() > maxTileSize || imageSize.height() > maxTileSize) {
173cb93a386Sopenharmony_ci        *clippedSubset = determine_clipped_src_rect(rtSize.width(), rtSize.height(), clip, ctm,
174cb93a386Sopenharmony_ci                                                    srcToDst, imageSize, src);
175cb93a386Sopenharmony_ci        *tileSize = determine_tile_size(*clippedSubset, maxTileSize);
176cb93a386Sopenharmony_ci        return true;
177cb93a386Sopenharmony_ci    }
178cb93a386Sopenharmony_ci
179cb93a386Sopenharmony_ci    // If the image would only produce 4 tiles of the smaller size, don't bother tiling it.
180cb93a386Sopenharmony_ci    const size_t area = imageSize.width() * imageSize.height();
181cb93a386Sopenharmony_ci    if (area < 4 * kBmpSmallTileSize * kBmpSmallTileSize) {
182cb93a386Sopenharmony_ci        return false;
183cb93a386Sopenharmony_ci    }
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ci    // At this point we know we could do the draw by uploading the entire bitmap as a texture.
186cb93a386Sopenharmony_ci    // However, if the texture would be large compared to the cache size and we don't require most
187cb93a386Sopenharmony_ci    // of it for this draw then tile to reduce the amount of upload and cache spill.
188cb93a386Sopenharmony_ci    // NOTE: if the context is not a direct context, it doesn't have access to the resource cache,
189cb93a386Sopenharmony_ci    // and theoretically, the resource cache's limits could be being changed on another thread, so
190cb93a386Sopenharmony_ci    // even having access to just the limit wouldn't be a reliable test during recording here.
191cb93a386Sopenharmony_ci    // Instead, we will just upload the entire image to be on the safe side and not tile.
192cb93a386Sopenharmony_ci    auto direct = context->asDirectContext();
193cb93a386Sopenharmony_ci    if (!direct) {
194cb93a386Sopenharmony_ci        return false;
195cb93a386Sopenharmony_ci    }
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_ci    // assumption here is that sw bitmap size is a good proxy for its size as
198cb93a386Sopenharmony_ci    // a texture
199cb93a386Sopenharmony_ci    size_t bmpSize = area * sizeof(SkPMColor);  // assume 32bit pixels
200cb93a386Sopenharmony_ci    size_t cacheSize = direct->getResourceCacheLimit();
201cb93a386Sopenharmony_ci    if (bmpSize < cacheSize / 2) {
202cb93a386Sopenharmony_ci        return false;
203cb93a386Sopenharmony_ci    }
204cb93a386Sopenharmony_ci
205cb93a386Sopenharmony_ci    // Figure out how much of the src we will need based on the src rect and clipping. Reject if
206cb93a386Sopenharmony_ci    // tiling memory savings would be < 50%.
207cb93a386Sopenharmony_ci    *clippedSubset = determine_clipped_src_rect(rtSize.width(), rtSize.height(), clip, ctm,
208cb93a386Sopenharmony_ci                                                srcToDst, imageSize, src);
209cb93a386Sopenharmony_ci    *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile.
210cb93a386Sopenharmony_ci    size_t usedTileBytes = get_tile_count(*clippedSubset, kBmpSmallTileSize) *
211cb93a386Sopenharmony_ci                           kBmpSmallTileSize * kBmpSmallTileSize *
212cb93a386Sopenharmony_ci                           sizeof(SkPMColor);  // assume 32bit pixels;
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ci    return usedTileBytes * 2 < bmpSize;
215cb93a386Sopenharmony_ci}
216cb93a386Sopenharmony_ci
217cb93a386Sopenharmony_ci// This method outsets 'iRect' by 'outset' all around and then clamps its extents to
218cb93a386Sopenharmony_ci// 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner
219cb93a386Sopenharmony_ci// of 'iRect' for all possible outsets/clamps.
220cb93a386Sopenharmony_ciinline void clamped_outset_with_offset(SkIRect* iRect, int outset, SkPoint* offset,
221cb93a386Sopenharmony_ci                                       const SkIRect& clamp) {
222cb93a386Sopenharmony_ci    iRect->outset(outset, outset);
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_ci    int leftClampDelta = clamp.fLeft - iRect->fLeft;
225cb93a386Sopenharmony_ci    if (leftClampDelta > 0) {
226cb93a386Sopenharmony_ci        offset->fX -= outset - leftClampDelta;
227cb93a386Sopenharmony_ci        iRect->fLeft = clamp.fLeft;
228cb93a386Sopenharmony_ci    } else {
229cb93a386Sopenharmony_ci        offset->fX -= outset;
230cb93a386Sopenharmony_ci    }
231cb93a386Sopenharmony_ci
232cb93a386Sopenharmony_ci    int topClampDelta = clamp.fTop - iRect->fTop;
233cb93a386Sopenharmony_ci    if (topClampDelta > 0) {
234cb93a386Sopenharmony_ci        offset->fY -= outset - topClampDelta;
235cb93a386Sopenharmony_ci        iRect->fTop = clamp.fTop;
236cb93a386Sopenharmony_ci    } else {
237cb93a386Sopenharmony_ci        offset->fY -= outset;
238cb93a386Sopenharmony_ci    }
239cb93a386Sopenharmony_ci
240cb93a386Sopenharmony_ci    if (iRect->fRight > clamp.fRight) {
241cb93a386Sopenharmony_ci        iRect->fRight = clamp.fRight;
242cb93a386Sopenharmony_ci    }
243cb93a386Sopenharmony_ci    if (iRect->fBottom > clamp.fBottom) {
244cb93a386Sopenharmony_ci        iRect->fBottom = clamp.fBottom;
245cb93a386Sopenharmony_ci    }
246cb93a386Sopenharmony_ci}
247cb93a386Sopenharmony_ci
248cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
249cb93a386Sopenharmony_ci//  Helper functions for drawing an image with v1::SurfaceDrawContext
250cb93a386Sopenharmony_ci
251cb93a386Sopenharmony_cienum class ImageDrawMode {
252cb93a386Sopenharmony_ci    // Src and dst have been restricted to the image content. May need to clamp, no need to decal.
253cb93a386Sopenharmony_ci    kOptimized,
254cb93a386Sopenharmony_ci    // Src and dst are their original sizes, requires use of a decal instead of plain clamping.
255cb93a386Sopenharmony_ci    // This is used when a dst clip is provided and extends outside of the optimized dst rect.
256cb93a386Sopenharmony_ci    kDecal,
257cb93a386Sopenharmony_ci    // Src or dst are empty, or do not intersect the image content so don't draw anything.
258cb93a386Sopenharmony_ci    kSkip
259cb93a386Sopenharmony_ci};
260cb93a386Sopenharmony_ci
261cb93a386Sopenharmony_ci/**
262cb93a386Sopenharmony_ci * Optimize the src rect sampling area within an image (sized 'width' x 'height') such that
263cb93a386Sopenharmony_ci * 'outSrcRect' will be completely contained in the image's bounds. The corresponding rect
264cb93a386Sopenharmony_ci * to draw will be output to 'outDstRect'. The mapping between src and dst will be cached in
265cb93a386Sopenharmony_ci * 'srcToDst'. Outputs are not always updated when kSkip is returned.
266cb93a386Sopenharmony_ci *
267cb93a386Sopenharmony_ci * If 'origSrcRect' is null, implicitly use the image bounds. If 'origDstRect' is null, use the
268cb93a386Sopenharmony_ci * original src rect. 'dstClip' should be null when there is no additional clipping.
269cb93a386Sopenharmony_ci */
270cb93a386Sopenharmony_ciImageDrawMode optimize_sample_area(const SkISize& image, const SkRect* origSrcRect,
271cb93a386Sopenharmony_ci                                   const SkRect* origDstRect, const SkPoint dstClip[4],
272cb93a386Sopenharmony_ci                                   SkRect* outSrcRect, SkRect* outDstRect,
273cb93a386Sopenharmony_ci                                   SkMatrix* srcToDst) {
274cb93a386Sopenharmony_ci    SkRect srcBounds = SkRect::MakeIWH(image.fWidth, image.fHeight);
275cb93a386Sopenharmony_ci
276cb93a386Sopenharmony_ci    SkRect src = origSrcRect ? *origSrcRect : srcBounds;
277cb93a386Sopenharmony_ci    SkRect dst = origDstRect ? *origDstRect : src;
278cb93a386Sopenharmony_ci
279cb93a386Sopenharmony_ci    if (src.isEmpty() || dst.isEmpty()) {
280cb93a386Sopenharmony_ci        return ImageDrawMode::kSkip;
281cb93a386Sopenharmony_ci    }
282cb93a386Sopenharmony_ci
283cb93a386Sopenharmony_ci    if (outDstRect) {
284cb93a386Sopenharmony_ci        *srcToDst = SkMatrix::RectToRect(src, dst);
285cb93a386Sopenharmony_ci    } else {
286cb93a386Sopenharmony_ci        srcToDst->setIdentity();
287cb93a386Sopenharmony_ci    }
288cb93a386Sopenharmony_ci
289cb93a386Sopenharmony_ci    if (origSrcRect && !srcBounds.contains(src)) {
290cb93a386Sopenharmony_ci        if (!src.intersect(srcBounds)) {
291cb93a386Sopenharmony_ci            return ImageDrawMode::kSkip;
292cb93a386Sopenharmony_ci        }
293cb93a386Sopenharmony_ci        srcToDst->mapRect(&dst, src);
294cb93a386Sopenharmony_ci
295cb93a386Sopenharmony_ci        // Both src and dst have gotten smaller. If dstClip is provided, confirm it is still
296cb93a386Sopenharmony_ci        // contained in dst, otherwise cannot optimize the sample area and must use a decal instead
297cb93a386Sopenharmony_ci        if (dstClip) {
298cb93a386Sopenharmony_ci            for (int i = 0; i < 4; ++i) {
299cb93a386Sopenharmony_ci                if (!dst.contains(dstClip[i].fX, dstClip[i].fY)) {
300cb93a386Sopenharmony_ci                    // Must resort to using a decal mode restricted to the clipped 'src', and
301cb93a386Sopenharmony_ci                    // use the original dst rect (filling in src bounds as needed)
302cb93a386Sopenharmony_ci                    *outSrcRect = src;
303cb93a386Sopenharmony_ci                    *outDstRect = (origDstRect ? *origDstRect
304cb93a386Sopenharmony_ci                                               : (origSrcRect ? *origSrcRect : srcBounds));
305cb93a386Sopenharmony_ci                    return ImageDrawMode::kDecal;
306cb93a386Sopenharmony_ci                }
307cb93a386Sopenharmony_ci            }
308cb93a386Sopenharmony_ci        }
309cb93a386Sopenharmony_ci    }
310cb93a386Sopenharmony_ci
311cb93a386Sopenharmony_ci    // The original src and dst were fully contained in the image, or there was no dst clip to
312cb93a386Sopenharmony_ci    // worry about, or the clip was still contained in the restricted dst rect.
313cb93a386Sopenharmony_ci    *outSrcRect = src;
314cb93a386Sopenharmony_ci    *outDstRect = dst;
315cb93a386Sopenharmony_ci    return ImageDrawMode::kOptimized;
316cb93a386Sopenharmony_ci}
317cb93a386Sopenharmony_ci
318cb93a386Sopenharmony_ci/**
319cb93a386Sopenharmony_ci * Checks whether the paint is compatible with using SurfaceDrawContext::drawTexture. It is more
320cb93a386Sopenharmony_ci * efficient than the SkImage general case.
321cb93a386Sopenharmony_ci */
322cb93a386Sopenharmony_cibool can_use_draw_texture(const SkPaint& paint, bool useCubicResampler, SkMipmapMode mm) {
323cb93a386Sopenharmony_ci    return (!paint.getColorFilter() && !paint.getShader() && !paint.getMaskFilter() &&
324cb93a386Sopenharmony_ci            !paint.getImageFilter() && !paint.getBlender() && !useCubicResampler &&
325cb93a386Sopenharmony_ci            mm == SkMipmapMode::kNone);
326cb93a386Sopenharmony_ci}
327cb93a386Sopenharmony_ci
328cb93a386Sopenharmony_ciSkPMColor4f texture_color(SkColor4f paintColor, float entryAlpha, GrColorType srcColorType,
329cb93a386Sopenharmony_ci                          const GrColorInfo& dstColorInfo) {
330cb93a386Sopenharmony_ci    paintColor.fA *= entryAlpha;
331cb93a386Sopenharmony_ci    if (GrColorTypeIsAlphaOnly(srcColorType)) {
332cb93a386Sopenharmony_ci        return SkColor4fPrepForDst(paintColor, dstColorInfo).premul();
333cb93a386Sopenharmony_ci    } else {
334cb93a386Sopenharmony_ci        float paintAlpha = SkTPin(paintColor.fA, 0.f, 1.f);
335cb93a386Sopenharmony_ci        return { paintAlpha, paintAlpha, paintAlpha, paintAlpha };
336cb93a386Sopenharmony_ci    }
337cb93a386Sopenharmony_ci}
338cb93a386Sopenharmony_ci
339cb93a386Sopenharmony_ci// Assumes srcRect and dstRect have already been optimized to fit the proxy
340cb93a386Sopenharmony_civoid draw_texture(skgpu::v1::SurfaceDrawContext* sdc,
341cb93a386Sopenharmony_ci                  const GrClip* clip,
342cb93a386Sopenharmony_ci                  const SkMatrix& ctm,
343cb93a386Sopenharmony_ci                  const SkPaint& paint,
344cb93a386Sopenharmony_ci                  GrSamplerState::Filter filter,
345cb93a386Sopenharmony_ci                  const SkRect& srcRect,
346cb93a386Sopenharmony_ci                  const SkRect& dstRect,
347cb93a386Sopenharmony_ci                  const SkPoint dstClip[4],
348cb93a386Sopenharmony_ci                  GrAA aa,
349cb93a386Sopenharmony_ci                  GrQuadAAFlags aaFlags,
350cb93a386Sopenharmony_ci                  SkCanvas::SrcRectConstraint constraint,
351cb93a386Sopenharmony_ci                  GrSurfaceProxyView view,
352cb93a386Sopenharmony_ci                  const GrColorInfo& srcColorInfo) {
353cb93a386Sopenharmony_ci    if (GrColorTypeIsAlphaOnly(srcColorInfo.colorType())) {
354cb93a386Sopenharmony_ci        view.concatSwizzle(GrSwizzle("aaaa"));
355cb93a386Sopenharmony_ci    }
356cb93a386Sopenharmony_ci    const GrColorInfo& dstInfo = sdc->colorInfo();
357cb93a386Sopenharmony_ci    auto textureXform = GrColorSpaceXform::Make(srcColorInfo, sdc->colorInfo());
358cb93a386Sopenharmony_ci    GrSurfaceProxy* proxy = view.proxy();
359cb93a386Sopenharmony_ci    // Must specify the strict constraint when the proxy is not functionally exact and the src
360cb93a386Sopenharmony_ci    // rect would access pixels outside the proxy's content area without the constraint.
361cb93a386Sopenharmony_ci    if (constraint != SkCanvas::kStrict_SrcRectConstraint && !proxy->isFunctionallyExact()) {
362cb93a386Sopenharmony_ci        // Conservative estimate of how much a coord could be outset from src rect:
363cb93a386Sopenharmony_ci        // 1/2 pixel for AA and 1/2 pixel for linear filtering
364cb93a386Sopenharmony_ci        float buffer = 0.5f * (aa == GrAA::kYes) +
365cb93a386Sopenharmony_ci                       0.5f * (filter == GrSamplerState::Filter::kLinear);
366cb93a386Sopenharmony_ci        SkRect safeBounds = proxy->getBoundsRect();
367cb93a386Sopenharmony_ci        safeBounds.inset(buffer, buffer);
368cb93a386Sopenharmony_ci        if (!safeBounds.contains(srcRect)) {
369cb93a386Sopenharmony_ci            constraint = SkCanvas::kStrict_SrcRectConstraint;
370cb93a386Sopenharmony_ci        }
371cb93a386Sopenharmony_ci    }
372cb93a386Sopenharmony_ci
373cb93a386Sopenharmony_ci    SkPMColor4f color = texture_color(paint.getColor4f(), 1.f, srcColorInfo.colorType(), dstInfo);
374cb93a386Sopenharmony_ci    if (dstClip) {
375cb93a386Sopenharmony_ci        // Get source coords corresponding to dstClip
376cb93a386Sopenharmony_ci        SkPoint srcQuad[4];
377cb93a386Sopenharmony_ci        GrMapRectPoints(dstRect, srcRect, dstClip, srcQuad, 4);
378cb93a386Sopenharmony_ci
379cb93a386Sopenharmony_ci        sdc->drawTextureQuad(clip,
380cb93a386Sopenharmony_ci                             std::move(view),
381cb93a386Sopenharmony_ci                             srcColorInfo.colorType(),
382cb93a386Sopenharmony_ci                             srcColorInfo.alphaType(),
383cb93a386Sopenharmony_ci                             filter,
384cb93a386Sopenharmony_ci                             GrSamplerState::MipmapMode::kNone,
385cb93a386Sopenharmony_ci                             paint.getBlendMode_or(SkBlendMode::kSrcOver),
386cb93a386Sopenharmony_ci                             color,
387cb93a386Sopenharmony_ci                             srcQuad,
388cb93a386Sopenharmony_ci                             dstClip,
389cb93a386Sopenharmony_ci                             aa,
390cb93a386Sopenharmony_ci                             aaFlags,
391cb93a386Sopenharmony_ci                             constraint == SkCanvas::kStrict_SrcRectConstraint ? &srcRect : nullptr,
392cb93a386Sopenharmony_ci                             ctm,
393cb93a386Sopenharmony_ci                             std::move(textureXform));
394cb93a386Sopenharmony_ci    } else {
395cb93a386Sopenharmony_ci        sdc->drawTexture(clip,
396cb93a386Sopenharmony_ci                         std::move(view),
397cb93a386Sopenharmony_ci                         srcColorInfo.alphaType(),
398cb93a386Sopenharmony_ci                         filter,
399cb93a386Sopenharmony_ci                         GrSamplerState::MipmapMode::kNone,
400cb93a386Sopenharmony_ci                         paint.getBlendMode_or(SkBlendMode::kSrcOver),
401cb93a386Sopenharmony_ci                         color,
402cb93a386Sopenharmony_ci                         srcRect,
403cb93a386Sopenharmony_ci                         dstRect,
404cb93a386Sopenharmony_ci                         aa,
405cb93a386Sopenharmony_ci                         aaFlags,
406cb93a386Sopenharmony_ci                         constraint,
407cb93a386Sopenharmony_ci                         ctm,
408cb93a386Sopenharmony_ci                         std::move(textureXform));
409cb93a386Sopenharmony_ci    }
410cb93a386Sopenharmony_ci}
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ci// Assumes srcRect and dstRect have already been optimized to fit the proxy.
413cb93a386Sopenharmony_civoid draw_image(GrRecordingContext* rContext,
414cb93a386Sopenharmony_ci                skgpu::v1::SurfaceDrawContext* sdc,
415cb93a386Sopenharmony_ci                const GrClip* clip,
416cb93a386Sopenharmony_ci                const SkMatrixProvider& matrixProvider,
417cb93a386Sopenharmony_ci                const SkPaint& paint,
418cb93a386Sopenharmony_ci                const SkImage_Base& image,
419cb93a386Sopenharmony_ci                const SkRect& src,
420cb93a386Sopenharmony_ci                const SkRect& dst,
421cb93a386Sopenharmony_ci                const SkPoint dstClip[4],
422cb93a386Sopenharmony_ci                const SkMatrix& srcToDst,
423cb93a386Sopenharmony_ci                GrAA aa,
424cb93a386Sopenharmony_ci                GrQuadAAFlags aaFlags,
425cb93a386Sopenharmony_ci                SkCanvas::SrcRectConstraint constraint,
426cb93a386Sopenharmony_ci                SkSamplingOptions sampling,
427cb93a386Sopenharmony_ci                SkTileMode tm = SkTileMode::kClamp) {
428cb93a386Sopenharmony_ci    const SkMatrix& ctm(matrixProvider.localToDevice());
429cb93a386Sopenharmony_ci    if (tm == SkTileMode::kClamp &&
430cb93a386Sopenharmony_ci        !image.isYUVA()          &&
431cb93a386Sopenharmony_ci        can_use_draw_texture(paint, sampling.useCubic, sampling.mipmap)) {
432cb93a386Sopenharmony_ci        // We've done enough checks above to allow us to pass ClampNearest() and not check for
433cb93a386Sopenharmony_ci        // scaling adjustments.
434cb93a386Sopenharmony_ci        auto [view, ct] = image.asView(rContext, GrMipmapped::kNo);
435cb93a386Sopenharmony_ci        if (!view) {
436cb93a386Sopenharmony_ci            return;
437cb93a386Sopenharmony_ci        }
438cb93a386Sopenharmony_ci        GrColorInfo info(image.imageInfo().colorInfo());
439cb93a386Sopenharmony_ci        info = info.makeColorType(ct);
440cb93a386Sopenharmony_ci        draw_texture(sdc,
441cb93a386Sopenharmony_ci                     clip,
442cb93a386Sopenharmony_ci                     ctm,
443cb93a386Sopenharmony_ci                     paint,
444cb93a386Sopenharmony_ci                     sampling.filter,
445cb93a386Sopenharmony_ci                     src,
446cb93a386Sopenharmony_ci                     dst,
447cb93a386Sopenharmony_ci                     dstClip,
448cb93a386Sopenharmony_ci                     aa,
449cb93a386Sopenharmony_ci                     aaFlags,
450cb93a386Sopenharmony_ci                     constraint,
451cb93a386Sopenharmony_ci                     std::move(view),
452cb93a386Sopenharmony_ci                     info);
453cb93a386Sopenharmony_ci        return;
454cb93a386Sopenharmony_ci    }
455cb93a386Sopenharmony_ci
456cb93a386Sopenharmony_ci    const SkMaskFilter* mf = paint.getMaskFilter();
457cb93a386Sopenharmony_ci
458cb93a386Sopenharmony_ci    // The shader expects proper local coords, so we can't replace local coords with texture coords
459cb93a386Sopenharmony_ci    // if the shader will be used. If we have a mask filter we will change the underlying geometry
460cb93a386Sopenharmony_ci    // that is rendered.
461cb93a386Sopenharmony_ci    bool canUseTextureCoordsAsLocalCoords = !use_shader(image.isAlphaOnly(), paint) && !mf;
462cb93a386Sopenharmony_ci
463cb93a386Sopenharmony_ci    // Specifying the texture coords as local coordinates is an attempt to enable more GrDrawOp
464cb93a386Sopenharmony_ci    // combining by not baking anything about the srcRect, dstRect, or ctm, into the texture
465cb93a386Sopenharmony_ci    // FP. In the future this should be an opaque optimization enabled by the combination of
466cb93a386Sopenharmony_ci    // GrDrawOp/GP and FP.
467cb93a386Sopenharmony_ci    if (mf && as_MFB(mf)->hasFragmentProcessor()) {
468cb93a386Sopenharmony_ci        mf = nullptr;
469cb93a386Sopenharmony_ci    }
470cb93a386Sopenharmony_ci
471cb93a386Sopenharmony_ci    bool restrictToSubset = SkCanvas::kStrict_SrcRectConstraint == constraint;
472cb93a386Sopenharmony_ci
473cb93a386Sopenharmony_ci    // If we have to outset for AA then we will generate texture coords outside the src rect. The
474cb93a386Sopenharmony_ci    // same happens for any mask filter that extends the bounds rendered in the dst.
475cb93a386Sopenharmony_ci    // This is conservative as a mask filter does not have to expand the bounds rendered.
476cb93a386Sopenharmony_ci    bool coordsAllInsideSrcRect = aaFlags == GrQuadAAFlags::kNone && !mf;
477cb93a386Sopenharmony_ci
478cb93a386Sopenharmony_ci    // Check for optimization to drop the src rect constraint when using linear filtering.
479cb93a386Sopenharmony_ci    // TODO: Just rely on image to handle this.
480cb93a386Sopenharmony_ci    if (!sampling.useCubic                       &&
481cb93a386Sopenharmony_ci        sampling.filter == SkFilterMode::kLinear &&
482cb93a386Sopenharmony_ci        restrictToSubset                         &&
483cb93a386Sopenharmony_ci        sampling.mipmap == SkMipmapMode::kNone   &&
484cb93a386Sopenharmony_ci        coordsAllInsideSrcRect                   &&
485cb93a386Sopenharmony_ci        !image.isYUVA()) {
486cb93a386Sopenharmony_ci        SkMatrix combinedMatrix;
487cb93a386Sopenharmony_ci        combinedMatrix.setConcat(ctm, srcToDst);
488cb93a386Sopenharmony_ci        if (can_ignore_linear_filtering_subset(src, combinedMatrix, sdc->numSamples())) {
489cb93a386Sopenharmony_ci            restrictToSubset = false;
490cb93a386Sopenharmony_ci        }
491cb93a386Sopenharmony_ci    }
492cb93a386Sopenharmony_ci
493cb93a386Sopenharmony_ci    SkMatrix textureMatrix;
494cb93a386Sopenharmony_ci    if (canUseTextureCoordsAsLocalCoords) {
495cb93a386Sopenharmony_ci        textureMatrix = SkMatrix::I();
496cb93a386Sopenharmony_ci    } else {
497cb93a386Sopenharmony_ci        if (!srcToDst.invert(&textureMatrix)) {
498cb93a386Sopenharmony_ci            return;
499cb93a386Sopenharmony_ci        }
500cb93a386Sopenharmony_ci    }
501cb93a386Sopenharmony_ci    const SkRect* subset = restrictToSubset       ? &src : nullptr;
502cb93a386Sopenharmony_ci    const SkRect* domain = coordsAllInsideSrcRect ? &src : nullptr;
503cb93a386Sopenharmony_ci    SkTileMode tileModes[] = {tm, tm};
504cb93a386Sopenharmony_ci    std::unique_ptr<GrFragmentProcessor> fp = image.asFragmentProcessor(rContext,
505cb93a386Sopenharmony_ci                                                                        sampling,
506cb93a386Sopenharmony_ci                                                                        tileModes,
507cb93a386Sopenharmony_ci                                                                        textureMatrix,
508cb93a386Sopenharmony_ci                                                                        subset,
509cb93a386Sopenharmony_ci                                                                        domain);
510cb93a386Sopenharmony_ci    fp = GrColorSpaceXformEffect::Make(std::move(fp),
511cb93a386Sopenharmony_ci                                       image.imageInfo().colorInfo(),
512cb93a386Sopenharmony_ci                                       sdc->colorInfo());
513cb93a386Sopenharmony_ci    if (image.isAlphaOnly()) {
514cb93a386Sopenharmony_ci        if (const auto* shader = as_SB(paint.getShader())) {
515cb93a386Sopenharmony_ci            auto shaderFP = shader->asFragmentProcessor(
516cb93a386Sopenharmony_ci                    GrFPArgs(rContext, matrixProvider, &sdc->colorInfo()));
517cb93a386Sopenharmony_ci            if (!shaderFP) {
518cb93a386Sopenharmony_ci                return;
519cb93a386Sopenharmony_ci            }
520cb93a386Sopenharmony_ci            fp = GrBlendFragmentProcessor::Make(
521cb93a386Sopenharmony_ci                    std::move(fp), std::move(shaderFP), SkBlendMode::kDstIn);
522cb93a386Sopenharmony_ci        } else {
523cb93a386Sopenharmony_ci            // Multiply the input (paint) color by the texture (alpha)
524cb93a386Sopenharmony_ci            fp = GrFragmentProcessor::MulInputByChildAlpha(std::move(fp));
525cb93a386Sopenharmony_ci        }
526cb93a386Sopenharmony_ci    }
527cb93a386Sopenharmony_ci
528cb93a386Sopenharmony_ci    GrPaint grPaint;
529cb93a386Sopenharmony_ci    if (!SkPaintToGrPaintReplaceShader(
530cb93a386Sopenharmony_ci                rContext, sdc->colorInfo(), paint, matrixProvider, std::move(fp), &grPaint)) {
531cb93a386Sopenharmony_ci        return;
532cb93a386Sopenharmony_ci    }
533cb93a386Sopenharmony_ci
534cb93a386Sopenharmony_ci    if (!mf) {
535cb93a386Sopenharmony_ci        // Can draw the image directly (any mask filter on the paint was converted to an FP already)
536cb93a386Sopenharmony_ci        if (dstClip) {
537cb93a386Sopenharmony_ci            SkPoint srcClipPoints[4];
538cb93a386Sopenharmony_ci            SkPoint* srcClip = nullptr;
539cb93a386Sopenharmony_ci            if (canUseTextureCoordsAsLocalCoords) {
540cb93a386Sopenharmony_ci                // Calculate texture coordinates that match the dst clip
541cb93a386Sopenharmony_ci                GrMapRectPoints(dst, src, dstClip, srcClipPoints, 4);
542cb93a386Sopenharmony_ci                srcClip = srcClipPoints;
543cb93a386Sopenharmony_ci            }
544cb93a386Sopenharmony_ci            sdc->fillQuadWithEdgeAA(clip, std::move(grPaint), aa, aaFlags, ctm, dstClip, srcClip);
545cb93a386Sopenharmony_ci        } else {
546cb93a386Sopenharmony_ci            // Provide explicit texture coords when possible, otherwise rely on texture matrix
547cb93a386Sopenharmony_ci            sdc->fillRectWithEdgeAA(clip, std::move(grPaint), aa, aaFlags, ctm, dst,
548cb93a386Sopenharmony_ci                                    canUseTextureCoordsAsLocalCoords ? &src : nullptr);
549cb93a386Sopenharmony_ci        }
550cb93a386Sopenharmony_ci    } else {
551cb93a386Sopenharmony_ci        // Must draw the mask filter as a GrStyledShape. For now, this loses the per-edge AA
552cb93a386Sopenharmony_ci        // information since it always draws with AA, but that should not be noticeable since the
553cb93a386Sopenharmony_ci        // mask filter is probably a blur.
554cb93a386Sopenharmony_ci        GrStyledShape shape;
555cb93a386Sopenharmony_ci        if (dstClip) {
556cb93a386Sopenharmony_ci            // Represent it as an SkPath formed from the dstClip
557cb93a386Sopenharmony_ci            SkPath path;
558cb93a386Sopenharmony_ci            path.addPoly(dstClip, 4, true);
559cb93a386Sopenharmony_ci            shape = GrStyledShape(path);
560cb93a386Sopenharmony_ci        } else {
561cb93a386Sopenharmony_ci            shape = GrStyledShape(dst);
562cb93a386Sopenharmony_ci        }
563cb93a386Sopenharmony_ci
564cb93a386Sopenharmony_ci        GrBlurUtils::drawShapeWithMaskFilter(
565cb93a386Sopenharmony_ci                rContext, sdc, clip, shape, std::move(grPaint), ctm, mf);
566cb93a386Sopenharmony_ci    }
567cb93a386Sopenharmony_ci}
568cb93a386Sopenharmony_ci
569cb93a386Sopenharmony_civoid draw_tiled_bitmap(GrRecordingContext* rContext,
570cb93a386Sopenharmony_ci                       skgpu::v1::SurfaceDrawContext* sdc,
571cb93a386Sopenharmony_ci                       const GrClip* clip,
572cb93a386Sopenharmony_ci                       const SkBitmap& bitmap,
573cb93a386Sopenharmony_ci                       int tileSize,
574cb93a386Sopenharmony_ci                       const SkMatrixProvider& matrixProvider,
575cb93a386Sopenharmony_ci                       const SkMatrix& srcToDst,
576cb93a386Sopenharmony_ci                       const SkRect& srcRect,
577cb93a386Sopenharmony_ci                       const SkIRect& clippedSrcIRect,
578cb93a386Sopenharmony_ci                       const SkPaint& paint,
579cb93a386Sopenharmony_ci                       GrAA aa,
580cb93a386Sopenharmony_ci                       SkCanvas::SrcRectConstraint constraint,
581cb93a386Sopenharmony_ci                       SkSamplingOptions sampling,
582cb93a386Sopenharmony_ci                       SkTileMode tileMode) {
583cb93a386Sopenharmony_ci    SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
584cb93a386Sopenharmony_ci
585cb93a386Sopenharmony_ci    int nx = bitmap.width() / tileSize;
586cb93a386Sopenharmony_ci    int ny = bitmap.height() / tileSize;
587cb93a386Sopenharmony_ci
588cb93a386Sopenharmony_ci    for (int x = 0; x <= nx; x++) {
589cb93a386Sopenharmony_ci        for (int y = 0; y <= ny; y++) {
590cb93a386Sopenharmony_ci            SkRect tileR;
591cb93a386Sopenharmony_ci            tileR.setLTRB(SkIntToScalar(x * tileSize),       SkIntToScalar(y * tileSize),
592cb93a386Sopenharmony_ci                          SkIntToScalar((x + 1) * tileSize), SkIntToScalar((y + 1) * tileSize));
593cb93a386Sopenharmony_ci
594cb93a386Sopenharmony_ci            if (!SkRect::Intersects(tileR, clippedSrcRect)) {
595cb93a386Sopenharmony_ci                continue;
596cb93a386Sopenharmony_ci            }
597cb93a386Sopenharmony_ci
598cb93a386Sopenharmony_ci            if (!tileR.intersect(srcRect)) {
599cb93a386Sopenharmony_ci                continue;
600cb93a386Sopenharmony_ci            }
601cb93a386Sopenharmony_ci
602cb93a386Sopenharmony_ci            SkIRect iTileR;
603cb93a386Sopenharmony_ci            tileR.roundOut(&iTileR);
604cb93a386Sopenharmony_ci            SkVector offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft),
605cb93a386Sopenharmony_ci                                            SkIntToScalar(iTileR.fTop));
606cb93a386Sopenharmony_ci            SkRect rectToDraw = tileR;
607cb93a386Sopenharmony_ci            srcToDst.mapRect(&rectToDraw);
608cb93a386Sopenharmony_ci            if (sampling.filter != SkFilterMode::kNearest || sampling.useCubic) {
609cb93a386Sopenharmony_ci                SkIRect iClampRect;
610cb93a386Sopenharmony_ci
611cb93a386Sopenharmony_ci                if (SkCanvas::kFast_SrcRectConstraint == constraint) {
612cb93a386Sopenharmony_ci                    // In bleed mode we want to always expand the tile on all edges
613cb93a386Sopenharmony_ci                    // but stay within the bitmap bounds
614cb93a386Sopenharmony_ci                    iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height());
615cb93a386Sopenharmony_ci                } else {
616cb93a386Sopenharmony_ci                    // In texture-domain/clamp mode we only want to expand the
617cb93a386Sopenharmony_ci                    // tile on edges interior to "srcRect" (i.e., we want to
618cb93a386Sopenharmony_ci                    // not bleed across the original clamped edges)
619cb93a386Sopenharmony_ci                    srcRect.roundOut(&iClampRect);
620cb93a386Sopenharmony_ci                }
621cb93a386Sopenharmony_ci                int outset = sampling.useCubic ? GrBicubicEffect::kFilterTexelPad : 1;
622cb93a386Sopenharmony_ci                clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect);
623cb93a386Sopenharmony_ci            }
624cb93a386Sopenharmony_ci
625cb93a386Sopenharmony_ci            // We must subset as a bitmap and then turn into an SkImage if we want caching to work.
626cb93a386Sopenharmony_ci            // Image subsets always make a copy of the pixels and lose the association with the
627cb93a386Sopenharmony_ci            // original's SkPixelRef.
628cb93a386Sopenharmony_ci            if (SkBitmap subsetBmp; bitmap.extractSubset(&subsetBmp, iTileR)) {
629cb93a386Sopenharmony_ci                auto image = SkMakeImageFromRasterBitmap(subsetBmp, kNever_SkCopyPixelsMode);
630cb93a386Sopenharmony_ci                // We should have already handled bitmaps larger than the max texture size.
631cb93a386Sopenharmony_ci                SkASSERT(image->width()  <= rContext->priv().caps()->maxTextureSize() &&
632cb93a386Sopenharmony_ci                         image->height() <= rContext->priv().caps()->maxTextureSize());
633cb93a386Sopenharmony_ci
634cb93a386Sopenharmony_ci                GrQuadAAFlags aaFlags = GrQuadAAFlags::kNone;
635cb93a386Sopenharmony_ci                if (aa == GrAA::kYes) {
636cb93a386Sopenharmony_ci                    // If the entire bitmap was anti-aliased, turn on AA for the outside tile edges.
637cb93a386Sopenharmony_ci                    if (tileR.fLeft <= srcRect.fLeft) {
638cb93a386Sopenharmony_ci                        aaFlags |= GrQuadAAFlags::kLeft;
639cb93a386Sopenharmony_ci                    }
640cb93a386Sopenharmony_ci                    if (tileR.fRight >= srcRect.fRight) {
641cb93a386Sopenharmony_ci                        aaFlags |= GrQuadAAFlags::kRight;
642cb93a386Sopenharmony_ci                    }
643cb93a386Sopenharmony_ci                    if (tileR.fTop <= srcRect.fTop) {
644cb93a386Sopenharmony_ci                        aaFlags |= GrQuadAAFlags::kTop;
645cb93a386Sopenharmony_ci                    }
646cb93a386Sopenharmony_ci                    if (tileR.fBottom >= srcRect.fBottom) {
647cb93a386Sopenharmony_ci                        aaFlags |= GrQuadAAFlags::kBottom;
648cb93a386Sopenharmony_ci                    }
649cb93a386Sopenharmony_ci                }
650cb93a386Sopenharmony_ci
651cb93a386Sopenharmony_ci                // now offset it to make it "local" to our tmp bitmap
652cb93a386Sopenharmony_ci                tileR.offset(-offset.fX, -offset.fY);
653cb93a386Sopenharmony_ci                SkMatrix offsetSrcToDst = srcToDst;
654cb93a386Sopenharmony_ci                offsetSrcToDst.preTranslate(offset.fX, offset.fY);
655cb93a386Sopenharmony_ci                draw_image(rContext,
656cb93a386Sopenharmony_ci                           sdc,
657cb93a386Sopenharmony_ci                           clip,
658cb93a386Sopenharmony_ci                           matrixProvider,
659cb93a386Sopenharmony_ci                           paint,
660cb93a386Sopenharmony_ci                           *as_IB(image.get()),
661cb93a386Sopenharmony_ci                           tileR,
662cb93a386Sopenharmony_ci                           rectToDraw,
663cb93a386Sopenharmony_ci                           nullptr,
664cb93a386Sopenharmony_ci                           offsetSrcToDst,
665cb93a386Sopenharmony_ci                           aa,
666cb93a386Sopenharmony_ci                           aaFlags,
667cb93a386Sopenharmony_ci                           constraint,
668cb93a386Sopenharmony_ci                           sampling,
669cb93a386Sopenharmony_ci                           tileMode);
670cb93a386Sopenharmony_ci            }
671cb93a386Sopenharmony_ci        }
672cb93a386Sopenharmony_ci    }
673cb93a386Sopenharmony_ci}
674cb93a386Sopenharmony_ci
675cb93a386Sopenharmony_ciSkFilterMode downgrade_to_filter(const SkSamplingOptions& sampling) {
676cb93a386Sopenharmony_ci    SkFilterMode filter = sampling.filter;
677cb93a386Sopenharmony_ci    if (sampling.useCubic || sampling.mipmap != SkMipmapMode::kNone) {
678cb93a386Sopenharmony_ci        // if we were "fancier" than just bilerp, only do bilerp
679cb93a386Sopenharmony_ci        filter = SkFilterMode::kLinear;
680cb93a386Sopenharmony_ci    }
681cb93a386Sopenharmony_ci    return filter;
682cb93a386Sopenharmony_ci}
683cb93a386Sopenharmony_ci
684cb93a386Sopenharmony_cibool can_disable_mipmap(const SkMatrix& viewM,
685cb93a386Sopenharmony_ci                        const SkMatrix& localM,
686cb93a386Sopenharmony_ci                        bool sharpenMipmappedTextures) {
687cb93a386Sopenharmony_ci    SkMatrix matrix;
688cb93a386Sopenharmony_ci    matrix.setConcat(viewM, localM);
689cb93a386Sopenharmony_ci    // With sharp mips, we bias lookups by -0.5. That means our final LOD is >= 0 until
690cb93a386Sopenharmony_ci    // the computed LOD is >= 0.5. At what scale factor does a texture get an LOD of
691cb93a386Sopenharmony_ci    // 0.5?
692cb93a386Sopenharmony_ci    //
693cb93a386Sopenharmony_ci    // Want:  0       = log2(1/s) - 0.5
694cb93a386Sopenharmony_ci    //        0.5     = log2(1/s)
695cb93a386Sopenharmony_ci    //        2^0.5   = 1/s
696cb93a386Sopenharmony_ci    //        1/2^0.5 = s
697cb93a386Sopenharmony_ci    //        2^0.5/2 = s
698cb93a386Sopenharmony_ci    SkScalar mipScale = sharpenMipmappedTextures ? SK_ScalarRoot2Over2 : SK_Scalar1;
699cb93a386Sopenharmony_ci    return matrix.getMinScale() >= mipScale;
700cb93a386Sopenharmony_ci}
701cb93a386Sopenharmony_ci
702cb93a386Sopenharmony_ci} // anonymous namespace
703cb93a386Sopenharmony_ci
704cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
705cb93a386Sopenharmony_ci
706cb93a386Sopenharmony_cinamespace skgpu::v1 {
707cb93a386Sopenharmony_ci
708cb93a386Sopenharmony_civoid Device::drawSpecial(SkSpecialImage* special,
709cb93a386Sopenharmony_ci                         const SkMatrix& localToDevice,
710cb93a386Sopenharmony_ci                         const SkSamplingOptions& origSampling,
711cb93a386Sopenharmony_ci                         const SkPaint& paint) {
712cb93a386Sopenharmony_ci    SkASSERT(!paint.getMaskFilter() && !paint.getImageFilter());
713cb93a386Sopenharmony_ci    SkASSERT(special->isTextureBacked());
714cb93a386Sopenharmony_ci
715cb93a386Sopenharmony_ci    SkRect src = SkRect::Make(special->subset());
716cb93a386Sopenharmony_ci    SkRect dst = SkRect::MakeWH(special->width(), special->height());
717cb93a386Sopenharmony_ci    SkMatrix srcToDst = SkMatrix::RectToRect(src, dst);
718cb93a386Sopenharmony_ci
719cb93a386Sopenharmony_ci    SkSamplingOptions sampling = SkSamplingOptions(downgrade_to_filter(origSampling));
720cb93a386Sopenharmony_ci    GrAA aa = fSurfaceDrawContext->chooseAA(paint);
721cb93a386Sopenharmony_ci    GrQuadAAFlags aaFlags = (aa == GrAA::kYes) ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
722cb93a386Sopenharmony_ci
723cb93a386Sopenharmony_ci    SkColorInfo colorInfo(special->colorType(),
724cb93a386Sopenharmony_ci                          special->alphaType(),
725cb93a386Sopenharmony_ci                          sk_ref_sp(special->getColorSpace()));
726cb93a386Sopenharmony_ci
727cb93a386Sopenharmony_ci    GrSurfaceProxyView view = special->view(this->recordingContext());
728cb93a386Sopenharmony_ci    SkImage_Gpu image(sk_ref_sp(special->getContext()),
729cb93a386Sopenharmony_ci                      special->uniqueID(),
730cb93a386Sopenharmony_ci                      std::move(view),
731cb93a386Sopenharmony_ci                      std::move(colorInfo));
732cb93a386Sopenharmony_ci    // In most cases this ought to hit draw_texture since there won't be a color filter,
733cb93a386Sopenharmony_ci    // alpha-only texture+shader, or a high filter quality.
734cb93a386Sopenharmony_ci    SkOverrideDeviceMatrixProvider matrixProvider(this->asMatrixProvider(), localToDevice);
735cb93a386Sopenharmony_ci    draw_image(fContext.get(),
736cb93a386Sopenharmony_ci               fSurfaceDrawContext.get(),
737cb93a386Sopenharmony_ci               this->clip(),
738cb93a386Sopenharmony_ci               matrixProvider,
739cb93a386Sopenharmony_ci               paint,
740cb93a386Sopenharmony_ci               image,
741cb93a386Sopenharmony_ci               src,
742cb93a386Sopenharmony_ci               dst,
743cb93a386Sopenharmony_ci               nullptr,
744cb93a386Sopenharmony_ci               srcToDst,
745cb93a386Sopenharmony_ci               aa,
746cb93a386Sopenharmony_ci               aaFlags,
747cb93a386Sopenharmony_ci               SkCanvas::kStrict_SrcRectConstraint,
748cb93a386Sopenharmony_ci               sampling);
749cb93a386Sopenharmony_ci}
750cb93a386Sopenharmony_ci
751cb93a386Sopenharmony_civoid Device::drawImageQuad(const SkImage* image,
752cb93a386Sopenharmony_ci                           const SkRect* srcRect,
753cb93a386Sopenharmony_ci                           const SkRect* dstRect,
754cb93a386Sopenharmony_ci                           const SkPoint dstClip[4],
755cb93a386Sopenharmony_ci                           GrAA aa,
756cb93a386Sopenharmony_ci                           GrQuadAAFlags aaFlags,
757cb93a386Sopenharmony_ci                           const SkMatrix* preViewMatrix,
758cb93a386Sopenharmony_ci                           const SkSamplingOptions& origSampling,
759cb93a386Sopenharmony_ci                           const SkPaint& paint,
760cb93a386Sopenharmony_ci                           SkCanvas::SrcRectConstraint constraint) {
761cb93a386Sopenharmony_ci    SkRect src;
762cb93a386Sopenharmony_ci    SkRect dst;
763cb93a386Sopenharmony_ci    SkMatrix srcToDst;
764cb93a386Sopenharmony_ci    ImageDrawMode mode = optimize_sample_area(SkISize::Make(image->width(), image->height()),
765cb93a386Sopenharmony_ci                                              srcRect, dstRect, dstClip, &src, &dst, &srcToDst);
766cb93a386Sopenharmony_ci    if (mode == ImageDrawMode::kSkip) {
767cb93a386Sopenharmony_ci        return;
768cb93a386Sopenharmony_ci    }
769cb93a386Sopenharmony_ci
770cb93a386Sopenharmony_ci    // OH ISSUE: restricting the drawing of abnormal processes
771cb93a386Sopenharmony_ci    if (fContext->isPidAbnormal()) {
772cb93a386Sopenharmony_ci        return;
773cb93a386Sopenharmony_ci    }
774cb93a386Sopenharmony_ci
775cb93a386Sopenharmony_ci    if (src.contains(image->bounds())) {
776cb93a386Sopenharmony_ci        constraint = SkCanvas::kFast_SrcRectConstraint;
777cb93a386Sopenharmony_ci    }
778cb93a386Sopenharmony_ci    // Depending on the nature of image, it can flow through more or less optimal pipelines
779cb93a386Sopenharmony_ci    SkTileMode tileMode = mode == ImageDrawMode::kDecal ? SkTileMode::kDecal : SkTileMode::kClamp;
780cb93a386Sopenharmony_ci
781cb93a386Sopenharmony_ci    // Get final CTM matrix
782cb93a386Sopenharmony_ci    SkPreConcatMatrixProvider matrixProvider(this->asMatrixProvider(),
783cb93a386Sopenharmony_ci                                             preViewMatrix ? *preViewMatrix : SkMatrix::I());
784cb93a386Sopenharmony_ci    const SkMatrix& ctm(matrixProvider.localToDevice());
785cb93a386Sopenharmony_ci
786cb93a386Sopenharmony_ci    SkSamplingOptions sampling = origSampling;
787cb93a386Sopenharmony_ci    bool sharpenMM = fContext->priv().options().fSharpenMipmappedTextures;
788cb93a386Sopenharmony_ci    if (sampling.mipmap != SkMipmapMode::kNone && can_disable_mipmap(ctm, srcToDst, sharpenMM)) {
789cb93a386Sopenharmony_ci        sampling = SkSamplingOptions(sampling.filter);
790cb93a386Sopenharmony_ci    }
791cb93a386Sopenharmony_ci    auto clip = this->clip();
792cb93a386Sopenharmony_ci
793cb93a386Sopenharmony_ci    if (!image->isTextureBacked() && !as_IB(image)->isPinnedOnContext(fContext.get())) {
794cb93a386Sopenharmony_ci        int tileFilterPad;
795cb93a386Sopenharmony_ci        if (sampling.useCubic) {
796cb93a386Sopenharmony_ci            tileFilterPad = GrBicubicEffect::kFilterTexelPad;
797cb93a386Sopenharmony_ci        } else if (sampling.filter == SkFilterMode::kNearest) {
798cb93a386Sopenharmony_ci            tileFilterPad = 0;
799cb93a386Sopenharmony_ci        } else {
800cb93a386Sopenharmony_ci            tileFilterPad = 1;
801cb93a386Sopenharmony_ci        }
802cb93a386Sopenharmony_ci        int maxTileSize = fContext->priv().caps()->maxTextureSize() - 2*tileFilterPad;
803cb93a386Sopenharmony_ci        int tileSize;
804cb93a386Sopenharmony_ci        SkIRect clippedSubset;
805cb93a386Sopenharmony_ci        if (should_tile_image_id(fContext.get(),
806cb93a386Sopenharmony_ci                                 fSurfaceDrawContext->dimensions(),
807cb93a386Sopenharmony_ci                                 clip,
808cb93a386Sopenharmony_ci                                 image->unique(),
809cb93a386Sopenharmony_ci                                 image->dimensions(),
810cb93a386Sopenharmony_ci                                 ctm,
811cb93a386Sopenharmony_ci                                 srcToDst,
812cb93a386Sopenharmony_ci                                 &src,
813cb93a386Sopenharmony_ci                                 maxTileSize,
814cb93a386Sopenharmony_ci                                 &tileSize,
815cb93a386Sopenharmony_ci                                 &clippedSubset)) {
816cb93a386Sopenharmony_ci            // Extract pixels on the CPU, since we have to split into separate textures before
817cb93a386Sopenharmony_ci            // sending to the GPU if tiling.
818cb93a386Sopenharmony_ci            if (SkBitmap bm; as_IB(image)->getROPixels(nullptr, &bm)) {
819cb93a386Sopenharmony_ci                // This is the funnel for all paths that draw tiled bitmaps/images.
820cb93a386Sopenharmony_ci                draw_tiled_bitmap(fContext.get(),
821cb93a386Sopenharmony_ci                                  fSurfaceDrawContext.get(),
822cb93a386Sopenharmony_ci                                  clip,
823cb93a386Sopenharmony_ci                                  bm,
824cb93a386Sopenharmony_ci                                  tileSize,
825cb93a386Sopenharmony_ci                                  matrixProvider,
826cb93a386Sopenharmony_ci                                  srcToDst,
827cb93a386Sopenharmony_ci                                  src,
828cb93a386Sopenharmony_ci                                  clippedSubset,
829cb93a386Sopenharmony_ci                                  paint,
830cb93a386Sopenharmony_ci                                  aa,
831cb93a386Sopenharmony_ci                                  constraint,
832cb93a386Sopenharmony_ci                                  sampling,
833cb93a386Sopenharmony_ci                                  tileMode);
834cb93a386Sopenharmony_ci                return;
835cb93a386Sopenharmony_ci            }
836cb93a386Sopenharmony_ci        }
837cb93a386Sopenharmony_ci    }
838cb93a386Sopenharmony_ci
839cb93a386Sopenharmony_ci    draw_image(fContext.get(),
840cb93a386Sopenharmony_ci               fSurfaceDrawContext.get(),
841cb93a386Sopenharmony_ci               clip,
842cb93a386Sopenharmony_ci               matrixProvider,
843cb93a386Sopenharmony_ci               paint,
844cb93a386Sopenharmony_ci               *as_IB(image),
845cb93a386Sopenharmony_ci               src,
846cb93a386Sopenharmony_ci               dst,
847cb93a386Sopenharmony_ci               dstClip,
848cb93a386Sopenharmony_ci               srcToDst,
849cb93a386Sopenharmony_ci               aa,
850cb93a386Sopenharmony_ci               aaFlags,
851cb93a386Sopenharmony_ci               constraint,
852cb93a386Sopenharmony_ci               sampling);
853cb93a386Sopenharmony_ci    return;
854cb93a386Sopenharmony_ci}
855cb93a386Sopenharmony_ci
856cb93a386Sopenharmony_civoid Device::drawEdgeAAImageSet(const SkCanvas::ImageSetEntry set[], int count,
857cb93a386Sopenharmony_ci                                const SkPoint dstClips[], const SkMatrix preViewMatrices[],
858cb93a386Sopenharmony_ci                                const SkSamplingOptions& sampling, const SkPaint& paint,
859cb93a386Sopenharmony_ci                                SkCanvas::SrcRectConstraint constraint) {
860cb93a386Sopenharmony_ci    SkASSERT(count > 0);
861cb93a386Sopenharmony_ci    if (!can_use_draw_texture(paint, sampling.useCubic, sampling.mipmap)) {
862cb93a386Sopenharmony_ci        // Send every entry through drawImageQuad() to handle the more complicated paint
863cb93a386Sopenharmony_ci        int dstClipIndex = 0;
864cb93a386Sopenharmony_ci        for (int i = 0; i < count; ++i) {
865cb93a386Sopenharmony_ci            // Only no clip or quad clip are supported
866cb93a386Sopenharmony_ci            SkASSERT(!set[i].fHasClip || dstClips);
867cb93a386Sopenharmony_ci            SkASSERT(set[i].fMatrixIndex < 0 || preViewMatrices);
868cb93a386Sopenharmony_ci
869cb93a386Sopenharmony_ci            SkTCopyOnFirstWrite<SkPaint> entryPaint(paint);
870cb93a386Sopenharmony_ci            if (set[i].fAlpha != 1.f) {
871cb93a386Sopenharmony_ci                auto paintAlpha = paint.getAlphaf();
872cb93a386Sopenharmony_ci                entryPaint.writable()->setAlphaf(paintAlpha * set[i].fAlpha);
873cb93a386Sopenharmony_ci            }
874cb93a386Sopenharmony_ci            // Always send GrAA::kYes to preserve seaming across tiling in MSAA
875cb93a386Sopenharmony_ci            this->drawImageQuad(
876cb93a386Sopenharmony_ci                    set[i].fImage.get(), &set[i].fSrcRect, &set[i].fDstRect,
877cb93a386Sopenharmony_ci                    set[i].fHasClip ? dstClips + dstClipIndex : nullptr, GrAA::kYes,
878cb93a386Sopenharmony_ci                    SkToGrQuadAAFlags(set[i].fAAFlags),
879cb93a386Sopenharmony_ci                    set[i].fMatrixIndex < 0 ? nullptr : preViewMatrices + set[i].fMatrixIndex,
880cb93a386Sopenharmony_ci                    sampling, *entryPaint, constraint);
881cb93a386Sopenharmony_ci            dstClipIndex += 4 * set[i].fHasClip;
882cb93a386Sopenharmony_ci        }
883cb93a386Sopenharmony_ci        return;
884cb93a386Sopenharmony_ci    }
885cb93a386Sopenharmony_ci
886cb93a386Sopenharmony_ci    GrSamplerState::Filter filter = sampling.filter == SkFilterMode::kNearest
887cb93a386Sopenharmony_ci                                            ? GrSamplerState::Filter::kNearest
888cb93a386Sopenharmony_ci                                            : GrSamplerState::Filter::kLinear;
889cb93a386Sopenharmony_ci    SkBlendMode mode = paint.getBlendMode_or(SkBlendMode::kSrcOver);
890cb93a386Sopenharmony_ci
891cb93a386Sopenharmony_ci    SkAutoTArray<GrTextureSetEntry> textures(count);
892cb93a386Sopenharmony_ci    // We accumulate compatible proxies until we find an an incompatible one or reach the end and
893cb93a386Sopenharmony_ci    // issue the accumulated 'n' draws starting at 'base'. 'p' represents the number of proxy
894cb93a386Sopenharmony_ci    // switches that occur within the 'n' entries.
895cb93a386Sopenharmony_ci    int base = 0, n = 0, p = 0;
896cb93a386Sopenharmony_ci    auto draw = [&](int nextBase) {
897cb93a386Sopenharmony_ci        if (n > 0) {
898cb93a386Sopenharmony_ci            auto textureXform = GrColorSpaceXform::Make(set[base].fImage->imageInfo().colorInfo(),
899cb93a386Sopenharmony_ci                                                        fSurfaceDrawContext->colorInfo());
900cb93a386Sopenharmony_ci            fSurfaceDrawContext->drawTextureSet(this->clip(),
901cb93a386Sopenharmony_ci                                                textures.get() + base,
902cb93a386Sopenharmony_ci                                                n,
903cb93a386Sopenharmony_ci                                                p,
904cb93a386Sopenharmony_ci                                                filter,
905cb93a386Sopenharmony_ci                                                GrSamplerState::MipmapMode::kNone,
906cb93a386Sopenharmony_ci                                                mode,
907cb93a386Sopenharmony_ci                                                GrAA::kYes,
908cb93a386Sopenharmony_ci                                                constraint,
909cb93a386Sopenharmony_ci                                                this->localToDevice(),
910cb93a386Sopenharmony_ci                                                std::move(textureXform));
911cb93a386Sopenharmony_ci        }
912cb93a386Sopenharmony_ci        base = nextBase;
913cb93a386Sopenharmony_ci        n = 0;
914cb93a386Sopenharmony_ci        p = 0;
915cb93a386Sopenharmony_ci    };
916cb93a386Sopenharmony_ci    int dstClipIndex = 0;
917cb93a386Sopenharmony_ci    for (int i = 0; i < count; ++i) {
918cb93a386Sopenharmony_ci        SkASSERT(!set[i].fHasClip || dstClips);
919cb93a386Sopenharmony_ci        SkASSERT(set[i].fMatrixIndex < 0 || preViewMatrices);
920cb93a386Sopenharmony_ci
921cb93a386Sopenharmony_ci        // Manage the dst clip pointer tracking before any continues are used so we don't lose
922cb93a386Sopenharmony_ci        // our place in the dstClips array.
923cb93a386Sopenharmony_ci        const SkPoint* clip = set[i].fHasClip ? dstClips + dstClipIndex : nullptr;
924cb93a386Sopenharmony_ci        dstClipIndex += 4 * set[i].fHasClip;
925cb93a386Sopenharmony_ci
926cb93a386Sopenharmony_ci        // The default SkBaseDevice implementation is based on drawImageRect which does not allow
927cb93a386Sopenharmony_ci        // non-sorted src rects. TODO: Decide this is OK or make sure we handle it.
928cb93a386Sopenharmony_ci        if (!set[i].fSrcRect.isSorted()) {
929cb93a386Sopenharmony_ci            draw(i + 1);
930cb93a386Sopenharmony_ci            continue;
931cb93a386Sopenharmony_ci        }
932cb93a386Sopenharmony_ci
933cb93a386Sopenharmony_ci        GrSurfaceProxyView view;
934cb93a386Sopenharmony_ci        const SkImage_Base* image = as_IB(set[i].fImage.get());
935cb93a386Sopenharmony_ci        // Extract view from image, but skip YUV images so they get processed through
936cb93a386Sopenharmony_ci        // drawImageQuad and the proper effect to dynamically sample their planes.
937cb93a386Sopenharmony_ci        if (!image->isYUVA()) {
938cb93a386Sopenharmony_ci            std::tie(view, std::ignore) = image->asView(this->recordingContext(), GrMipmapped::kNo);
939cb93a386Sopenharmony_ci            if (image->isAlphaOnly()) {
940cb93a386Sopenharmony_ci                GrSwizzle swizzle = GrSwizzle::Concat(view.swizzle(), GrSwizzle("aaaa"));
941cb93a386Sopenharmony_ci                view = {view.detachProxy(), view.origin(), swizzle};
942cb93a386Sopenharmony_ci            }
943cb93a386Sopenharmony_ci        }
944cb93a386Sopenharmony_ci
945cb93a386Sopenharmony_ci        if (!view) {
946cb93a386Sopenharmony_ci            // This image can't go through the texture op, send through general image pipeline
947cb93a386Sopenharmony_ci            // after flushing current batch.
948cb93a386Sopenharmony_ci            draw(i + 1);
949cb93a386Sopenharmony_ci            SkTCopyOnFirstWrite<SkPaint> entryPaint(paint);
950cb93a386Sopenharmony_ci            if (set[i].fAlpha != 1.f) {
951cb93a386Sopenharmony_ci                auto paintAlpha = paint.getAlphaf();
952cb93a386Sopenharmony_ci                entryPaint.writable()->setAlphaf(paintAlpha * set[i].fAlpha);
953cb93a386Sopenharmony_ci            }
954cb93a386Sopenharmony_ci            this->drawImageQuad(
955cb93a386Sopenharmony_ci                    image, &set[i].fSrcRect, &set[i].fDstRect, clip, GrAA::kYes,
956cb93a386Sopenharmony_ci                    SkToGrQuadAAFlags(set[i].fAAFlags),
957cb93a386Sopenharmony_ci                    set[i].fMatrixIndex < 0 ? nullptr : preViewMatrices + set[i].fMatrixIndex,
958cb93a386Sopenharmony_ci                    sampling, *entryPaint, constraint);
959cb93a386Sopenharmony_ci            continue;
960cb93a386Sopenharmony_ci        }
961cb93a386Sopenharmony_ci
962cb93a386Sopenharmony_ci        textures[i].fProxyView = std::move(view);
963cb93a386Sopenharmony_ci        textures[i].fSrcAlphaType = image->alphaType();
964cb93a386Sopenharmony_ci        textures[i].fSrcRect = set[i].fSrcRect;
965cb93a386Sopenharmony_ci        textures[i].fDstRect = set[i].fDstRect;
966cb93a386Sopenharmony_ci        textures[i].fDstClipQuad = clip;
967cb93a386Sopenharmony_ci        textures[i].fPreViewMatrix =
968cb93a386Sopenharmony_ci                set[i].fMatrixIndex < 0 ? nullptr : preViewMatrices + set[i].fMatrixIndex;
969cb93a386Sopenharmony_ci        textures[i].fColor = texture_color(paint.getColor4f(), set[i].fAlpha,
970cb93a386Sopenharmony_ci                                           SkColorTypeToGrColorType(image->colorType()),
971cb93a386Sopenharmony_ci                                           fSurfaceDrawContext->colorInfo());
972cb93a386Sopenharmony_ci        textures[i].fAAFlags = SkToGrQuadAAFlags(set[i].fAAFlags);
973cb93a386Sopenharmony_ci
974cb93a386Sopenharmony_ci        if (n > 0 &&
975cb93a386Sopenharmony_ci            (!GrTextureProxy::ProxiesAreCompatibleAsDynamicState(
976cb93a386Sopenharmony_ci                    textures[i].fProxyView.proxy(),
977cb93a386Sopenharmony_ci                    textures[base].fProxyView.proxy()) ||
978cb93a386Sopenharmony_ci             textures[i].fProxyView.swizzle() != textures[base].fProxyView.swizzle() ||
979cb93a386Sopenharmony_ci             set[i].fImage->alphaType() != set[base].fImage->alphaType() ||
980cb93a386Sopenharmony_ci             !SkColorSpace::Equals(set[i].fImage->colorSpace(), set[base].fImage->colorSpace()))) {
981cb93a386Sopenharmony_ci            draw(i);
982cb93a386Sopenharmony_ci        }
983cb93a386Sopenharmony_ci        // Whether or not we submitted a draw in the above if(), this ith entry is in the current
984cb93a386Sopenharmony_ci        // set being accumulated so increment n, and increment p if proxies are different.
985cb93a386Sopenharmony_ci        ++n;
986cb93a386Sopenharmony_ci        if (n == 1 || textures[i - 1].fProxyView.proxy() != textures[i].fProxyView.proxy()) {
987cb93a386Sopenharmony_ci            // First proxy or a different proxy (that is compatible, otherwise we'd have drawn up
988cb93a386Sopenharmony_ci            // to i - 1).
989cb93a386Sopenharmony_ci            ++p;
990cb93a386Sopenharmony_ci        }
991cb93a386Sopenharmony_ci    }
992cb93a386Sopenharmony_ci    draw(count);
993cb93a386Sopenharmony_ci}
994cb93a386Sopenharmony_ci
995cb93a386Sopenharmony_ci} // namespace skgpu::v1
996