Flutter Engine
The Flutter Engine
SkImageShader.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
21#include "modules/skcms/skcms.h"
37
38#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
40#endif
41
42#include <optional>
43#include <tuple>
44#include <utility>
45
46class SkColorSpace;
47
49#if 0
50 constexpr SkM44 kMitchell = SkM44( 1.f/18.f, -9.f/18.f, 15.f/18.f, -7.f/18.f,
51 16.f/18.f, 0.f/18.f, -36.f/18.f, 21.f/18.f,
52 1.f/18.f, 9.f/18.f, 27.f/18.f, -21.f/18.f,
53 0.f/18.f, 0.f/18.f, -6.f/18.f, 7.f/18.f);
54
55 constexpr SkM44 kCatmull = SkM44(0.0f, -0.5f, 1.0f, -0.5f,
56 1.0f, 0.0f, -2.5f, 1.5f,
57 0.0f, 0.5f, 2.0f, -1.5f,
58 0.0f, 0.0f, -0.5f, 0.5f);
59
60 if (B == 1.0f/3 && C == 1.0f/3) {
61 return kMitchell;
62 }
63 if (B == 0 && C == 0.5f) {
64 return kCatmull;
65 }
66#endif
67 return SkM44( (1.f/6)*B, -(3.f/6)*B - C, (3.f/6)*B + 2*C, - (1.f/6)*B - C,
68 1 - (2.f/6)*B, 0, -3 + (12.f/6)*B + C, 2 - (9.f/6)*B - C,
69 (1.f/6)*B, (3.f/6)*B + C, 3 - (15.f/6)*B - 2*C, -2 + (9.f/6)*B + C,
70 0, 0, -C, (1.f/6)*B + C);
71}
72
73/**
74 * We are faster in clamp, so always use that tiling when we can.
75 */
76static SkTileMode optimize(SkTileMode tm, int dimension) {
77 SkASSERT(dimension > 0);
78#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
79 // need to update frameworks/base/libs/hwui/tests/unit/SkiaBehaviorTests.cpp:55 to allow
80 // for transforming to clamp.
81 return tm;
82#else
83 // mirror and repeat on a 1px axis are the same as clamping, but decal will still transition to
84 // transparent black.
85 return (tm != SkTileMode::kDecal && dimension == 1) ? SkTileMode::kClamp : tm;
86#endif
87}
88
89#if defined(SK_DEBUG)
90static bool needs_subset(SkImage* img, const SkRect& subset) {
91 return subset != SkRect::Make(img->dimensions());
92}
93#endif
94
96 const SkRect& subset,
99 bool raw,
100 bool clampAsIfUnpremul)
101 : fImage(std::move(img))
102 , fSampling(sampling)
103 , fTileModeX(optimize(tmx, fImage->width()))
104 , fTileModeY(optimize(tmy, fImage->height()))
105 , fSubset(subset)
106 , fRaw(raw)
107 , fClampAsIfUnpremul(clampAsIfUnpremul) {
108 // These options should never appear together:
109 SkASSERT(!fRaw || !fClampAsIfUnpremul);
110
111 // Bicubic filtering of raw image shaders would add a surprising clamp - so we don't support it
112 SkASSERT(!fRaw || !fSampling.useCubic);
113}
114
115// just used for legacy-unflattening
117 kNone,
118 kLow,
119 kMedium,
120 kHigh,
121 // this is the special value for backward compatibility
123 // this signals we should use the new SkFilterOptions
125 // use cubic and ignore FilterOptions
127
129};
130
131// fClampAsIfUnpremul is always false when constructed through public APIs,
132// so there's no need to read or write it here.
133
134sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
137
139 bool readSampling = true;
141 !buffer.readBool() /* legacy has_sampling */)
142 {
143 readSampling = false;
144 // we just default to Nearest in sampling
145 }
146 if (readSampling) {
147 sampling = buffer.readSampling();
148 }
149
150 SkMatrix localMatrix;
151 if (buffer.isVersionLT(SkPicturePriv::Version::kNoShaderLocalMatrix)) {
152 buffer.readMatrix(&localMatrix);
153 }
154 sk_sp<SkImage> img = buffer.readImage();
155 if (!img) {
156 return nullptr;
157 }
158
159 bool raw = buffer.isVersionLT(SkPicturePriv::Version::kRawImageShaders) ? false
160 : buffer.readBool();
161
162 // TODO(skbug.com/12784): Subset is not serialized yet; it's only used by special images so it
163 // will never be written to an SKP.
164
165 return raw ? SkImageShader::MakeRaw(std::move(img), tmx, tmy, sampling, &localMatrix)
166 : SkImageShader::Make(std::move(img), tmx, tmy, sampling, &localMatrix);
167}
168
169void SkImageShader::flatten(SkWriteBuffer& buffer) const {
170 buffer.writeUInt((unsigned)fTileModeX);
171 buffer.writeUInt((unsigned)fTileModeY);
172
173 buffer.writeSampling(fSampling);
174
175 buffer.writeImage(fImage.get());
176 SkASSERT(fClampAsIfUnpremul == false);
177
178 // TODO(skbug.com/12784): Subset is not serialized yet; it's only used by special images so it
179 // will never be written to an SKP.
180 SkASSERT(!needs_subset(fImage.get(), fSubset));
181
182 buffer.writeBool(fRaw);
183}
184
186 return fImage->isOpaque() &&
187 fTileModeX != SkTileMode::kDecal && fTileModeY != SkTileMode::kDecal;
188}
189
190#ifdef SK_ENABLE_LEGACY_SHADERCONTEXT
191
192static bool legacy_shader_can_handle(const SkMatrix& inv) {
193 SkASSERT(!inv.hasPerspective());
194
195 // Scale+translate methods are always present, but affine might not be.
196 if (!SkOpts::S32_alpha_D32_filter_DXDY && !inv.isScaleTranslate()) {
197 return false;
198 }
199
200 // legacy code uses SkFixed 32.32, so ensure the inverse doesn't map device coordinates
201 // out of range.
202 const SkScalar max_dev_coord = 32767.0f;
203 const SkRect src = inv.mapRect(SkRect::MakeWH(max_dev_coord, max_dev_coord));
204
205 // take 1/4 of max signed 32bits so we have room to subtract local values
206 const SkScalar max_fixed32dot32 = float(SK_MaxS32) * 0.25f;
207 if (!SkRect::MakeLTRB(-max_fixed32dot32, -max_fixed32dot32,
208 +max_fixed32dot32, +max_fixed32dot32).contains(src)) {
209 return false;
210 }
211
212 // legacy shader impl should be able to handle these matrices
213 return true;
214}
215
216SkShaderBase::Context* SkImageShader::onMakeContext(const ContextRec& rec,
217 SkArenaAlloc* alloc) const {
218 SkASSERT(!needs_subset(fImage.get(), fSubset)); // TODO(skbug.com/12784)
219 if (fImage->alphaType() == kUnpremul_SkAlphaType) {
220 return nullptr;
221 }
222 if (fImage->colorType() != kN32_SkColorType) {
223 return nullptr;
224 }
225 if (fTileModeX != fTileModeY) {
226 return nullptr;
227 }
228 if (fTileModeX == SkTileMode::kDecal || fTileModeY == SkTileMode::kDecal) {
229 return nullptr;
230 }
231
232 SkSamplingOptions sampling = fSampling;
233 if (sampling.isAniso()) {
235 }
236
237 auto supported = [](const SkSamplingOptions& sampling) {
238 const std::tuple<SkFilterMode,SkMipmapMode> supported[] = {
242 };
243 for (auto [f, m] : supported) {
244 if (sampling.filter == f && sampling.mipmap == m) {
245 return true;
246 }
247 }
248 return false;
249 };
250 if (sampling.useCubic || !supported(sampling)) {
251 return nullptr;
252 }
253
254 // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer,
255 // so it can't handle bitmaps larger than 65535.
256 //
257 // We back off another bit to 32767 to make small amounts of
258 // intermediate math safe, e.g. in
259 //
260 // SkFixed fx = ...;
261 // fx = tile(fx + SK_Fixed1);
262 //
263 // we want to make sure (fx + SK_Fixed1) never overflows.
264 if (fImage-> width() > 32767 ||
265 fImage->height() > 32767) {
266 return nullptr;
267 }
268
270 if (!rec.fMatrixRec.totalInverse(&inv) || !legacy_shader_can_handle(inv)) {
271 return nullptr;
272 }
273
274 if (!rec.isLegacyCompatible(fImage->colorSpace())) {
275 return nullptr;
276 }
277
278 return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY, sampling,
279 as_IB(fImage.get()), rec, alloc);
280}
281#endif
282
283SkImage* SkImageShader::onIsAImage(SkMatrix* texM, SkTileMode xy[]) const {
284 if (texM) {
285 *texM = SkMatrix::I();
286 }
287 if (xy) {
288 xy[0] = fTileModeX;
289 xy[1] = fTileModeY;
290 }
291 return const_cast<SkImage*>(fImage.get());
292}
293
297 const SkMatrix* localMatrix,
298 bool clampAsIfUnpremul) {
300 return MakeSubset(std::move(image), subset, tmx, tmy, options, localMatrix, clampAsIfUnpremul);
301}
302
306 const SkMatrix* localMatrix) {
307 if (options.useCubic) {
308 return nullptr;
309 }
310 if (!image) {
311 return SkShaders::Empty();
312 }
314
315 sk_sp<SkShader> s = sk_make_sp<SkImageShader>(image,
316 subset,
317 tmx, tmy,
318 options,
319 /*raw=*/true,
320 /*clampAsIfUnpremul=*/false);
321 return s->makeWithLocalMatrix(localMatrix ? *localMatrix : SkMatrix::I());
322}
323
325 const SkRect& subset,
328 const SkMatrix* localMatrix,
329 bool clampAsIfUnpremul) {
330 auto is_unit = [](float x) {
331 return x >= 0 && x <= 1;
332 };
333 if (options.useCubic) {
334 if (!is_unit(options.cubic.B) || !is_unit(options.cubic.C)) {
335 return nullptr;
336 }
337 }
338 if (!image || subset.isEmpty()) {
339 return SkShaders::Empty();
340 }
341
342 // Validate subset and check if we can drop it
344 return nullptr;
345 }
346
347 sk_sp<SkShader> s = sk_make_sp<SkImageShader>(std::move(image),
348 subset,
349 tmx, tmy,
350 options,
351 /*raw=*/false,
352 clampAsIfUnpremul);
353 return s->makeWithLocalMatrix(localMatrix ? *localMatrix : SkMatrix::I());
354}
355
356///////////////////////////////////////////////////////////////////////////////////////////////////
357
361 const SkMatrix* localMatrix, SkCopyPixelsMode mode) {
363 tmx, tmy, sampling, localMatrix);
364 if (!s) {
365 return nullptr;
366 }
367 if (SkColorTypeIsAlphaOnly(src.colorType()) && paint.getShader()) {
368 // Compose the image shader with the paint's shader. Alpha images+shaders should output the
369 // texture's alpha multiplied by the shader's color. DstIn (d*sa) will achieve this with
370 // the source image and dst shader (MakeBlend takes dst first, src second).
371 s = SkShaders::Blend(SkBlendMode::kDstIn, paint.refShader(), std::move(s));
372 }
373 return s;
374}
375
378 SkRect src,
379 SkRect dst,
380 bool strictSrcSubset,
381 SkPaint* paint) {
382 // The paint should have already been cleaned for a regular drawImageRect, e.g. no path
383 // effect and is a fill.
385 SkASSERT(paint->getStyle() == SkPaint::kFill_Style && !paint->getPathEffect());
386
388 SkRect imgBounds = SkRect::Make(image->bounds());
389
390 SkASSERT(src.isFinite() && dst.isFinite() && dst.isSorted());
391 SkMatrix localMatrix = SkMatrix::RectToRect(src, dst);
392 if (!imgBounds.contains(src)) {
393 if (!src.intersect(imgBounds)) {
394 return SkRect::MakeEmpty(); // Nothing to draw for this entry
395 }
396 // Update dst to match smaller src
397 dst = localMatrix.mapRect(src);
398 }
399
400 bool imageIsAlphaOnly = SkColorTypeIsAlphaOnly(image->colorType());
401
402 sk_sp<SkShader> imgShader;
403 if (strictSrcSubset) {
406 sampling, &localMatrix);
407 } else {
409 sampling, &localMatrix);
410 }
411 if (!imgShader) {
412 return SkRect::MakeEmpty();
413 }
414 if (imageIsAlphaOnly && paint->getShader()) {
415 // Compose the image shader with the paint's shader. Alpha images+shaders should output the
416 // texture's alpha multiplied by the shader's color. DstIn (d*sa) will achieve this with
417 // the source image and dst shader (MakeBlend takes dst first, src second).
418 imgShader = SkShaders::Blend(SkBlendMode::kDstIn, paint->refShader(), std::move(imgShader));
419 }
420
421 paint->setShader(std::move(imgShader));
422 return dst;
423}
424
426
427namespace {
428
429struct MipLevelHelper {
430 SkPixmap pm;
435 SkRasterPipeline_DecalTileCtx* decalCtx = nullptr;
436
437 void allocAndInit(SkArenaAlloc* alloc,
439 SkTileMode tileModeX,
440 SkTileMode tileModeY) {
442 gather->pixels = pm.addr();
443 gather->stride = pm.rowBytesAsPixels();
444 gather->width = pm.width();
445 gather->height = pm.height();
446
447 if (sampling.useCubic) {
449 .getColMajor(gather->weights);
450 }
451
452 limitX = alloc->make<SkRasterPipeline_TileCtx>();
453 limitY = alloc->make<SkRasterPipeline_TileCtx>();
454 limitX->scale = pm.width();
455 limitX->invScale = 1.0f / pm.width();
456 limitY->scale = pm.height();
457 limitY->invScale = 1.0f / pm.height();
458
459 // We would like an image that is mapped 1:1 with device pixels but at a half pixel offset
460 // to select every pixel from the src image once. Our rasterizer biases upward. That is a
461 // rect from 0.5...1.5 fills pixel 1 and not pixel 0. So we make exact integer pixel sample
462 // values select the pixel to the left/above the integer value.
463 //
464 // Note that a mirror mapping between canvas and image space will not have this property -
465 // on one side of the image a row/column will be skipped and one repeated on the other side.
466 //
467 // The GM nearest_half_pixel_image tests both of the above scenarios.
468 //
469 // The implementation of SkTileMode::kMirror also modifies integer pixel snapping to create
470 // consistency when the sample coords are running backwards and must account for gather
471 // modification we perform here. The GM mirror_tile tests this.
473 gather->roundDownAtInteger = true;
474 limitX->mirrorBiasDir = limitY->mirrorBiasDir = 1;
475 }
476
477 if (tileModeX == SkTileMode::kDecal || tileModeY == SkTileMode::kDecal) {
478 decalCtx = alloc->make<SkRasterPipeline_DecalTileCtx>();
479 decalCtx->limit_x = limitX->scale;
480 decalCtx->limit_y = limitY->scale;
481
482 // When integer sample coords snap left/up then we want the right/bottom edge of the
483 // image bounds to be inside the image rather than the left/top edge, that is (0, w]
484 // rather than [0, w).
485 if (gather->roundDownAtInteger) {
486 decalCtx->inclusiveEdge_x = decalCtx->limit_x;
487 decalCtx->inclusiveEdge_y = decalCtx->limit_y;
488 }
489 }
490 }
491};
492
493} // namespace
494
497
498 // When the matrix is just an integer translate, bilerp == nearest neighbor.
499 if (filter == SkFilterMode::kLinear &&
500 matrix.getType() <= SkMatrix::kTranslate_Mask &&
501 matrix.getTranslateX() == (int)matrix.getTranslateX() &&
502 matrix.getTranslateY() == (int)matrix.getTranslateY()) {
503 filter = SkFilterMode::kNearest;
504 }
505
506 return SkSamplingOptions(filter, sampling.mipmap);
507}
508
509bool SkImageShader::appendStages(const SkStageRec& rec, const SkShaders::MatrixRec& mRec) const {
510 SkASSERT(!needs_subset(fImage.get(), fSubset)); // TODO(skbug.com/12784)
511
512 // We only support certain sampling options in stages so far
513 auto sampling = fSampling;
514 if (sampling.isAniso()) {
516 }
517
519 SkArenaAlloc* alloc = rec.fAlloc;
520
521 SkMatrix baseInv;
522 // If the total matrix isn't valid then we will always access the base MIP level.
523 if (mRec.totalMatrixIsValid()) {
524 if (!mRec.totalInverse(&baseInv)) {
525 return false;
526 }
527 baseInv.normalizePerspective();
528 }
529
531 auto* access = SkMipmapAccessor::Make(alloc, fImage.get(), baseInv, sampling.mipmap);
532 if (!access) {
533 return false;
534 }
535
536 MipLevelHelper upper;
537 std::tie(upper.pm, upper.inv) = access->level();
538
539 if (!sampling.useCubic) {
540 // TODO: can tweak_sampling sometimes for cubic too when B=0
541 if (mRec.totalMatrixIsValid()) {
542 sampling = tweak_sampling(sampling, SkMatrix::Concat(upper.inv, baseInv));
543 }
544 }
545
546 if (!mRec.apply(rec, upper.inv)) {
547 return false;
548 }
549
550 upper.allocAndInit(alloc, sampling, fTileModeX, fTileModeY);
551
552 MipLevelHelper lower;
553 SkRasterPipeline_MipmapCtx* mipmapCtx = nullptr;
554 float lowerWeight = access->lowerWeight();
555 if (lowerWeight > 0) {
556 std::tie(lower.pm, lower.inv) = access->lowerLevel();
557 mipmapCtx = alloc->make<SkRasterPipeline_MipmapCtx>();
558 mipmapCtx->lowerWeight = lowerWeight;
559 mipmapCtx->scaleX = static_cast<float>(lower.pm.width()) / upper.pm.width();
560 mipmapCtx->scaleY = static_cast<float>(lower.pm.height()) / upper.pm.height();
561
562 lower.allocAndInit(alloc, sampling, fTileModeX, fTileModeY);
563
564 p->append(SkRasterPipelineOp::mipmap_linear_init, mipmapCtx);
565 }
566
567 const bool decalBothAxes = fTileModeX == SkTileMode::kDecal && fTileModeY == SkTileMode::kDecal;
568
569 auto append_tiling_and_gather = [&](const MipLevelHelper* level) {
570 if (decalBothAxes) {
571 p->append(SkRasterPipelineOp::decal_x_and_y, level->decalCtx);
572 } else {
573 switch (fTileModeX) {
574 case SkTileMode::kClamp: /* The gather_xxx stage will clamp for us. */
575 break;
577 p->append(SkRasterPipelineOp::mirror_x, level->limitX);
578 break;
580 p->append(SkRasterPipelineOp::repeat_x, level->limitX);
581 break;
583 p->append(SkRasterPipelineOp::decal_x, level->decalCtx);
584 break;
585 }
586 switch (fTileModeY) {
587 case SkTileMode::kClamp: /* The gather_xxx stage will clamp for us. */
588 break;
590 p->append(SkRasterPipelineOp::mirror_y, level->limitY);
591 break;
593 p->append(SkRasterPipelineOp::repeat_y, level->limitY);
594 break;
596 p->append(SkRasterPipelineOp::decal_y, level->decalCtx);
597 break;
598 }
599 }
600
601 void* ctx = level->gather;
602 switch (level->pm.colorType()) {
603 case kAlpha_8_SkColorType: p->append(SkRasterPipelineOp::gather_a8, ctx); break;
604 case kA16_unorm_SkColorType: p->append(SkRasterPipelineOp::gather_a16, ctx); break;
605 case kA16_float_SkColorType: p->append(SkRasterPipelineOp::gather_af16, ctx); break;
606 case kRGB_565_SkColorType: p->append(SkRasterPipelineOp::gather_565, ctx); break;
607 case kARGB_4444_SkColorType: p->append(SkRasterPipelineOp::gather_4444, ctx); break;
608 case kR8G8_unorm_SkColorType: p->append(SkRasterPipelineOp::gather_rg88, ctx); break;
609 case kR16G16_unorm_SkColorType: p->append(SkRasterPipelineOp::gather_rg1616,ctx); break;
610 case kR16G16_float_SkColorType: p->append(SkRasterPipelineOp::gather_rgf16, ctx); break;
611 case kRGBA_8888_SkColorType: p->append(SkRasterPipelineOp::gather_8888, ctx); break;
612
614 p->append(SkRasterPipelineOp::gather_1010102, ctx);
615 break;
616
618 p->append(SkRasterPipelineOp::gather_16161616, ctx);
619 break;
620
622 case kRGBA_F16_SkColorType: p->append(SkRasterPipelineOp::gather_f16, ctx); break;
623 case kRGBA_F32_SkColorType: p->append(SkRasterPipelineOp::gather_f32, ctx); break;
625 p->append(SkRasterPipelineOp::gather_10101010_xr, ctx);
626 p->append(SkRasterPipelineOp::swap_rb);
627 break;
628 case kRGBA_10x6_SkColorType: p->append(SkRasterPipelineOp::gather_10x6, ctx); break;
629
630 case kGray_8_SkColorType: p->append(SkRasterPipelineOp::gather_a8, ctx);
631 p->append(SkRasterPipelineOp::alpha_to_gray ); break;
632
633 case kR8_unorm_SkColorType: p->append(SkRasterPipelineOp::gather_a8, ctx);
634 p->append(SkRasterPipelineOp::alpha_to_red ); break;
635
636 case kRGB_888x_SkColorType: p->append(SkRasterPipelineOp::gather_8888, ctx);
637 p->append(SkRasterPipelineOp::force_opaque ); break;
638
640 p->append(SkRasterPipelineOp::gather_1010102, ctx);
641 p->append(SkRasterPipelineOp::swap_rb);
642 break;
643
645 p->append(SkRasterPipelineOp::gather_1010102, ctx);
646 p->append(SkRasterPipelineOp::force_opaque);
647 break;
648
650 p->append(SkRasterPipelineOp::gather_1010102_xr, ctx);
651 p->append(SkRasterPipelineOp::force_opaque);
652 p->append(SkRasterPipelineOp::swap_rb);
653 break;
654
656 p->append(SkRasterPipelineOp::gather_1010102, ctx);
657 p->append(SkRasterPipelineOp::force_opaque);
658 p->append(SkRasterPipelineOp::swap_rb);
659 break;
660
662 p->append(SkRasterPipelineOp::gather_8888, ctx);
663 p->append(SkRasterPipelineOp::swap_rb);
664 break;
665
667 p->append(SkRasterPipelineOp::gather_8888, ctx);
668 p->appendTransferFunction(*skcms_sRGB_TransferFunction());
669 break;
670
671 case kUnknown_SkColorType: SkASSERT(false);
672 }
673 if (level->decalCtx) {
674 p->append(SkRasterPipelineOp::check_decal_mask, level->decalCtx);
675 }
676 };
677
678 auto append_misc = [&] {
679 SkColorSpace* cs = upper.pm.colorSpace();
680 SkAlphaType at = upper.pm.alphaType();
681
682 // Color for alpha-only images comes from the paint (already converted to dst color space).
683 // If we were sampled by a runtime effect, the paint color was replaced with transparent
684 // black, so this tinting is effectively suppressed. See also: RuntimeEffectRPCallbacks
685 if (SkColorTypeIsAlphaOnly(upper.pm.colorType()) && !fRaw) {
686 p->appendSetRGB(alloc, rec.fPaintColor);
687
688 cs = rec.fDstCS;
690 }
691
692 // Bicubic filtering naturally produces out of range values on both sides of [0,1].
693 if (sampling.useCubic) {
694 p->append(at == kUnpremul_SkAlphaType || fClampAsIfUnpremul
695 ? SkRasterPipelineOp::clamp_01
696 : SkRasterPipelineOp::clamp_gamut);
697 }
698
699 // Transform color space and alpha type to match shader convention (dst CS, premul alpha).
700 if (!fRaw) {
702 }
703
704 return true;
705 };
706
707 // Check for fast-path stages.
708 // TODO: Could we use the fast-path stages for each level when doing linear mipmap filtering?
709 SkColorType ct = upper.pm.colorType();
710 if (true
714 && fTileModeX == SkTileMode::kClamp && fTileModeY == SkTileMode::kClamp) {
715
716 p->append(SkRasterPipelineOp::bilerp_clamp_8888, upper.gather);
717 if (ct == kBGRA_8888_SkColorType) {
718 p->append(SkRasterPipelineOp::swap_rb);
719 }
720 return append_misc();
721 }
722 if (true
725 && fTileModeX == SkTileMode::kClamp && fTileModeY == SkTileMode::kClamp) {
726
727 p->append(SkRasterPipelineOp::bicubic_clamp_8888, upper.gather);
728 if (ct == kBGRA_8888_SkColorType) {
729 p->append(SkRasterPipelineOp::swap_rb);
730 }
731 return append_misc();
732 }
733
734 // This context can be shared by both levels when doing linear mipmap filtering
736
737 auto sample = [&](SkRasterPipelineOp setup_x,
738 SkRasterPipelineOp setup_y,
739 const MipLevelHelper* level) {
740 p->append(setup_x, sampler);
741 p->append(setup_y, sampler);
742 append_tiling_and_gather(level);
743 p->append(SkRasterPipelineOp::accumulate, sampler);
744 };
745
746 auto sample_level = [&](const MipLevelHelper* level) {
747 if (sampling.useCubic) {
749
750 p->append(SkRasterPipelineOp::bicubic_setup, sampler);
751
752 sample(SkRasterPipelineOp::bicubic_n3x, SkRasterPipelineOp::bicubic_n3y, level);
753 sample(SkRasterPipelineOp::bicubic_n1x, SkRasterPipelineOp::bicubic_n3y, level);
754 sample(SkRasterPipelineOp::bicubic_p1x, SkRasterPipelineOp::bicubic_n3y, level);
755 sample(SkRasterPipelineOp::bicubic_p3x, SkRasterPipelineOp::bicubic_n3y, level);
756
757 sample(SkRasterPipelineOp::bicubic_n3x, SkRasterPipelineOp::bicubic_n1y, level);
758 sample(SkRasterPipelineOp::bicubic_n1x, SkRasterPipelineOp::bicubic_n1y, level);
759 sample(SkRasterPipelineOp::bicubic_p1x, SkRasterPipelineOp::bicubic_n1y, level);
760 sample(SkRasterPipelineOp::bicubic_p3x, SkRasterPipelineOp::bicubic_n1y, level);
761
762 sample(SkRasterPipelineOp::bicubic_n3x, SkRasterPipelineOp::bicubic_p1y, level);
763 sample(SkRasterPipelineOp::bicubic_n1x, SkRasterPipelineOp::bicubic_p1y, level);
764 sample(SkRasterPipelineOp::bicubic_p1x, SkRasterPipelineOp::bicubic_p1y, level);
765 sample(SkRasterPipelineOp::bicubic_p3x, SkRasterPipelineOp::bicubic_p1y, level);
766
767 sample(SkRasterPipelineOp::bicubic_n3x, SkRasterPipelineOp::bicubic_p3y, level);
768 sample(SkRasterPipelineOp::bicubic_n1x, SkRasterPipelineOp::bicubic_p3y, level);
769 sample(SkRasterPipelineOp::bicubic_p1x, SkRasterPipelineOp::bicubic_p3y, level);
770 sample(SkRasterPipelineOp::bicubic_p3x, SkRasterPipelineOp::bicubic_p3y, level);
771
772 p->append(SkRasterPipelineOp::move_dst_src);
773 } else if (sampling.filter == SkFilterMode::kLinear) {
774 p->append(SkRasterPipelineOp::bilinear_setup, sampler);
775
776 sample(SkRasterPipelineOp::bilinear_nx, SkRasterPipelineOp::bilinear_ny, level);
777 sample(SkRasterPipelineOp::bilinear_px, SkRasterPipelineOp::bilinear_ny, level);
778 sample(SkRasterPipelineOp::bilinear_nx, SkRasterPipelineOp::bilinear_py, level);
779 sample(SkRasterPipelineOp::bilinear_px, SkRasterPipelineOp::bilinear_py, level);
780
781 p->append(SkRasterPipelineOp::move_dst_src);
782 } else {
783 append_tiling_and_gather(level);
784 }
785 };
786
787 sample_level(&upper);
788
789 if (mipmapCtx) {
790 p->append(SkRasterPipelineOp::mipmap_linear_update, mipmapCtx);
791 sample_level(&lower);
792 p->append(SkRasterPipelineOp::mipmap_linear_finish, mipmapCtx);
793 }
794
795 return append_misc();
796}
797
798namespace SkShaders {
799
803 const SkMatrix* localMatrix) {
804 return SkImageShader::Make(std::move(image), tmx, tmy, options, localMatrix);
805}
806
810 const SkMatrix* localMatrix) {
811 return SkImageShader::MakeRaw(std::move(image), tmx, tmy, options, localMatrix);
812}
813
814} // namespace SkShaders
static SkM44 inv(const SkM44 &m)
Definition: 3d.cpp:26
const char * options
kUnpremul_SkAlphaType
SkAlphaType
Definition: SkAlphaType.h:26
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kDstIn
r = d * sa
SkColorType
Definition: SkColorType.h:19
@ kR16G16B16A16_unorm_SkColorType
pixel with a little endian uint16_t for red, green, blue
Definition: SkColorType.h:50
@ kRGBA_10x6_SkColorType
pixel with 10 used bits (most significant) followed by 6 unused
Definition: SkColorType.h:33
@ kR8_unorm_SkColorType
Definition: SkColorType.h:54
@ kBGR_101010x_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word
Definition: SkColorType.h:30
@ kARGB_4444_SkColorType
pixel with 4 bits for alpha, red, green, blue; in 16-bit word
Definition: SkColorType.h:23
@ kR8G8_unorm_SkColorType
pixel with a uint8_t for red and green
Definition: SkColorType.h:43
@ kBGRA_8888_SkColorType
pixel with 8 bits for blue, green, red, alpha; in 32-bit word
Definition: SkColorType.h:26
@ kA16_unorm_SkColorType
pixel with a little endian uint16_t for alpha
Definition: SkColorType.h:48
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition: SkColorType.h:21
@ kRGB_101010x_SkColorType
pixel with 10 bits each for red, green, blue; in 32-bit word
Definition: SkColorType.h:29
@ kSRGBA_8888_SkColorType
Definition: SkColorType.h:53
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
Definition: SkColorType.h:35
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition: SkColorType.h:22
@ kBGRA_10101010_XR_SkColorType
pixel with 10 bits each for blue, green, red, alpha; in 64-bit word, extended range
Definition: SkColorType.h:32
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
@ kRGB_888x_SkColorType
pixel with 8 bits each for red, green, blue; in 32-bit word
Definition: SkColorType.h:25
@ kBGRA_1010102_SkColorType
10 bits for blue, green, red; 2 bits for alpha; in 32-bit word
Definition: SkColorType.h:28
@ kA16_float_SkColorType
pixel with a half float for alpha
Definition: SkColorType.h:45
@ kRGBA_F32_SkColorType
pixel using C float for red, green, blue, alpha; in 128-bit word
Definition: SkColorType.h:40
@ kRGBA_1010102_SkColorType
10 bits for red, green, blue; 2 bits for alpha; in 32-bit word
Definition: SkColorType.h:27
@ kBGR_101010x_XR_SkColorType
pixel with 10 bits each for blue, green, red; in 32-bit word, extended range
Definition: SkColorType.h:31
@ kR16G16_unorm_SkColorType
pixel with a little endian uint16_t for red and green
Definition: SkColorType.h:49
@ kRGBA_F16Norm_SkColorType
pixel with half floats in [0,1] for red, green, blue, alpha;
Definition: SkColorType.h:36
@ kUnknown_SkColorType
uninitialized
Definition: SkColorType.h:20
@ kR16G16_float_SkColorType
pixel with a half float for red and green
Definition: SkColorType.h:46
#define SK_REGISTER_FLATTENABLE(type)
static bool SkColorTypeIsAlphaOnly(SkColorType ct)
SK_SPI sk_sp< SkImage > SkMakeImageFromRasterBitmap(const SkBitmap &, SkCopyPixelsMode)
SkCopyPixelsMode
Definition: SkImagePriv.h:17
LegacyFilterEnum
static SkSamplingOptions tweak_sampling(SkSamplingOptions sampling, const SkMatrix &matrix)
static SkTileMode optimize(SkTileMode tm, int dimension)
SkRect SkModifyPaintAndDstForDrawImageRect(const SkImage *image, const SkSamplingOptions &sampling, SkRect src, SkRect dst, bool strictSrcSubset, SkPaint *paint)
sk_sp< SkShader > SkMakeBitmapShaderForPaint(const SkPaint &paint, const SkBitmap &src, SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &sampling, const SkMatrix *localMatrix, SkCopyPixelsMode mode)
static SkImage_Base * as_IB(SkImage *image)
Definition: SkImage_Base.h:201
static constexpr int32_t SK_MaxS32
Definition: SkMath.h:21
static bool apply(Pass *pass, SkRecord *record)
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
SkFilterMode
SkTileMode
Definition: SkTileMode.h:13
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
Definition: SkArenaAlloc.h:120
SkSamplingOptions sampling() const
Definition: SkImageShader.h:69
static sk_sp< SkShader > Make(sk_sp< SkImage >, SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix, bool clampAsIfUnpremul=false)
static SkM44 CubicResamplerMatrix(float B, float C)
bool isOpaque() const override
static sk_sp< SkShader > MakeSubset(sk_sp< SkImage >, const SkRect &subset, SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix, bool clampAsIfUnpremul=false)
sk_sp< SkImage > image() const
Definition: SkImageShader.h:68
SkImageShader(sk_sp< SkImage >, const SkRect &subset, SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, bool raw, bool clampAsIfUnpremul)
static sk_sp< SkShader > MakeRaw(sk_sp< SkImage >, SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix)
SkRect subset() const
Definition: SkImageShader.h:70
SkColorSpace * colorSpace() const
Definition: SkImage.cpp:156
SkISize dimensions() const
Definition: SkImage.h:297
SkAlphaType alphaType() const
Definition: SkImage.cpp:154
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition: SkImage.cpp:179
SkColorType colorType() const
Definition: SkImage.cpp:152
bool isOpaque() const
Definition: SkImage.h:375
int height() const
Definition: SkImage.h:291
SkIRect bounds() const
Definition: SkImage.h:303
bool hasMipmaps() const
Definition: SkImage.cpp:292
Definition: SkM44.h:150
void getColMajor(SkScalar v[]) const
Definition: SkM44.h:256
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
Definition: SkMatrix.h:157
static SkMatrix Concat(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.h:1775
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
void normalizePerspective()
Definition: SkMatrix.h:1270
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
Definition: SkMatrix.cpp:1141
@ kTranslate_Mask
translation SkMatrix
Definition: SkMatrix.h:193
static SkMipmapAccessor * Make(SkArenaAlloc *, const SkImage *, const SkMatrix &inv, SkMipmapMode)
@ kFill_Style
set to fill geometry
Definition: SkPaint.h:193
@ kNoFilterQualityShaders_Version
int width() const
Definition: SkPixmap.h:160
int rowBytesAsPixels() const
Definition: SkPixmap.h:214
const void * addr() const
Definition: SkPixmap.h:153
int height() const
Definition: SkPixmap.h:166
static SkSamplingOptions AnisoFallback(bool imageIsMipped)
static void RegisterFlattenables()
std::optional< MatrixRec > apply(const SkStageRec &rec, const SkMatrix &postInv={}) const
bool totalInverse(SkMatrix *out) const
Definition: SkShaderBase.h:120
bool totalMatrixIsValid() const
Definition: SkShaderBase.h:110
T * get() const
Definition: SkRefCnt.h:303
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
struct MyStruct s
double x
static bool needs_subset(sk_sp< const SkImage > img, const SkRect &subset)
SI T gather(const T *p, U32 ix)
void(* S32_alpha_D32_filter_DXDY)(const SkBitmapProcState &, const uint32_t *xy, int count, SkPMColor *)
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
sk_sp< const SkImage > image
Definition: SkRecords.h:269
SkSamplingOptions sampling
Definition: SkRecords.h:337
SK_API sk_sp< SkShader > Blend(SkBlendMode mode, sk_sp< SkShader > dst, sk_sp< SkShader > src)
SK_API sk_sp< SkShader > RawImage(sk_sp< SkImage > image, SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &options, const SkMatrix *localMatrix=nullptr)
SK_API sk_sp< SkShader > Image(sk_sp< SkImage > image, SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &options, const SkMatrix *localMatrix=nullptr)
SK_API sk_sp< SkShader > Empty()
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
Definition: switches.h:228
dst
Definition: cp.py:12
SkSamplingOptions(SkFilterMode::kLinear))
constexpr bool contains(std::string_view str, std::string_view needle)
Definition: SkStringView.h:41
Definition: ref_ptr.h:256
SkTileMode tmy
SkTileMode tmx
int32_t height
int32_t width
const skcms_TransferFunction * skcms_sRGB_TransferFunction()
Definition: skcms.cc:1587
static SkRect Make(const SkISize &size)
Definition: SkRect.h:669
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
bool contains(SkScalar x, SkScalar y) const
Definition: extension.cpp:19
bool isEmpty() const
Definition: SkRect.h:693
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646
const SkCubicResampler cubic
const SkFilterMode filter
const SkMipmapMode mipmap
SkColor4f fPaintColor
Definition: SkEffectPriv.h:25
SkRasterPipeline * fPipeline
Definition: SkEffectPriv.h:21
SkColorSpace * fDstCS
Definition: SkEffectPriv.h:24
SkArenaAlloc * fAlloc
Definition: SkEffectPriv.h:22