Flutter Engine
The Flutter Engine
GrImageUtils.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2023 Google LLC
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
16#include "include/core/SkRect.h"
18#include "include/core/SkSize.h"
27#include "include/gpu/GrTypes.h"
39#include "src/gpu/ResourceKey.h"
41#include "src/gpu/Swizzle.h"
55#include "src/gpu/ganesh/SkGr.h"
68
69#include <string_view>
70#include <utility>
71
72class SkDevice;
73class SkMatrix;
74class SkSurfaceProps;
75enum SkColorType : int;
76
77#if defined(SK_USE_LEGACY_BLUR_GANESH)
83#else
84class SkSpecialImage;
85#endif
86
87namespace skgpu::ganesh {
88
91 skgpu::Mipmapped mipmapped,
93 std::string_view label) {
97 return GrSurfaceProxyView::Copy(context,
98 std::move(src),
99 mipmapped,
101 budgeted,
102 /*label=*/label);
103}
104
105std::tuple<GrSurfaceProxyView, GrColorType> RasterAsView(GrRecordingContext* rContext,
106 const SkImage_Raster* raster,
107 skgpu::Mipmapped mipmapped,
110 // If the draw doesn't require mipmaps but this SkImage has them go ahead and make a
111 // mipmapped texture. There are three reasons for this:
112 // 1) Avoiding another texture creation if a later draw requires mipmaps.
113 // 2) Ensuring we upload the bitmap's levels instead of generating on the GPU from the base.
114 if (raster->hasMipmaps()) {
115 mipmapped = skgpu::Mipmapped::kYes;
116 }
117 return GrMakeCachedBitmapProxyView(rContext,
118 raster->bitmap(),
119 /*label=*/"TextureForImageRasterWithPolicyEqualKDraw",
120 mipmapped);
121 }
126 rContext, raster->bitmap(), mipmapped, SkBackingFit::kExact, budgeted);
127}
128
129// Returns the GrColorType to use with the GrTextureProxy returned from lockTextureProxy. This
130// may be different from the color type on the image in the case where we need up upload CPU
131// data to a texture but the GPU doesn't support the format of CPU data. In this case we convert
132// the data to RGBA_8888 unorm on the CPU then upload that.
136 if (!format.isValid()) {
138 }
139 return ct;
140}
141
143 SkASSERT(img->generator());
144 if (!img->generator()->isTextureGenerator()) {
146 }
147 // origin should be thread safe
148 return static_cast<const GrTextureGenerator*>(img->generator()->fGenerator.get())->origin();
149}
150
151
153 const SkImage_Lazy* img,
154 skgpu::Budgeted budgeted) {
155 auto supportedDataTypes = SupportedTextureFormats(*ctx);
156 SkYUVAPixmaps yuvaPixmaps;
157 sk_sp<SkCachedData> dataStorage = img->getPlanes(supportedDataTypes, &yuvaPixmaps);
158 if (!dataStorage) {
159 return {};
160 }
161
163 GrColorType pixmapColorTypes[SkYUVAInfo::kMaxPlanes];
164 for (int i = 0; i < yuvaPixmaps.numPlanes(); ++i) {
165 // If the sizes of the components are not all the same we choose to create exact-match
166 // textures for the smaller ones rather than add a texture domain to the draw.
167 // TODO: revisit this decision to improve texture reuse?
168 SkBackingFit fit = yuvaPixmaps.plane(i).dimensions() == img->dimensions()
171
172 // We grab a ref to cached yuv data. When the SkBitmap we create below goes away it will
173 // call releaseProc which will release this ref.
174 // DDL TODO: Currently we end up creating a lazy proxy that will hold onto a ref to the
175 // SkImage in its lambda. This means that we'll keep the ref on the YUV data around for the
176 // life time of the proxy and not just upload. For non-DDL draws we should look into
177 // releasing this SkImage after uploads (by deleting the lambda after instantiation).
178 auto releaseProc = [](void*, void* data) {
179 auto cachedData = static_cast<SkCachedData*>(data);
180 SkASSERT(cachedData);
181 cachedData->unref();
182 };
184 bitmap.installPixels(yuvaPixmaps.plane(i).info(),
185 yuvaPixmaps.plane(i).writable_addr(),
186 yuvaPixmaps.plane(i).rowBytes(),
188 SkRef(dataStorage.get()));
189 bitmap.setImmutable();
190
191 std::tie(views[i], std::ignore) =
193 if (!views[i]) {
194 return {};
195 }
196 pixmapColorTypes[i] = SkColorTypeToGrColorType(bitmap.colorType());
197 }
198
199 // TODO: investigate preallocating mip maps here
202 /*color space*/ nullptr,
203 img->dimensions());
204
205 auto sfc = ctx->priv().makeSFC(info,
206 "ImageLazy_TextureProxyViewFromPlanes",
208 1,
212 budgeted);
213 if (!sfc) {
214 return {};
215 }
216
217 GrYUVATextureProxies yuvaProxies(yuvaPixmaps.yuvaInfo(), views, pixmapColorTypes);
218 SkAssertResult(yuvaProxies.isValid());
219
220 std::unique_ptr<GrFragmentProcessor> fp = GrYUVtoRGBEffect::Make(
221 yuvaProxies,
223 *ctx->priv().caps());
224
225 // The pixels after yuv->rgb will be in the generator's color space.
226 // If onMakeColorTypeAndColorSpace has been called then this will not match this image's
227 // color space. To correct this, apply a color space conversion from the generator's color
228 // space to this image's color space.
229 SkColorSpace* srcColorSpace = img->generator()->getInfo().colorSpace();
230 SkColorSpace* dstColorSpace = img->colorSpace();
231
232 // If the caller expects the pixels in a different color space than the one from the image,
233 // apply a color conversion to do this.
235 srcColorSpace, kOpaque_SkAlphaType,
236 dstColorSpace, kOpaque_SkAlphaType);
237 sfc->fillWithFP(std::move(fp));
238
239 return sfc->readSurfaceView();
240}
241
243 const SkImage_Picture* img,
244 skgpu::Mipmapped mipmapped,
245 GrImageTexGenPolicy texGenPolicy) {
246 SkASSERT(ctx);
247 SkASSERT(img);
248
253 budgeted,
254 img->imageInfo(),
255 0,
257 img->props(),
258 mipmapped == skgpu::Mipmapped::kYes);
259 if (!surface) {
260 return {};
261 }
262
263 img->replay(surface->getCanvas());
264
265 sk_sp<SkImage> image(surface->makeImageSnapshot());
266 if (!image) {
267 return {};
268 }
269
270 auto [view, ct] = AsView(ctx, image, mipmapped);
271 SkASSERT(view);
272 SkASSERT(mipmapped == skgpu::Mipmapped::kNo ||
273 view.asTextureProxy()->mipmapped() == skgpu::Mipmapped::kYes);
274 return view;
275}
276
277// Returns the texture proxy. We will always cache the generated texture on success.
278// We have 4 ways to try to return a texture (in sorted order)
279//
280// 1. Check the cache for a pre-existing one
281// 2. Ask the generator to natively create one
282// 3. Ask the generator to return YUV planes, which the GPU can convert
283// 4. Ask the generator to return RGB(A) data, which the GPU can convert
285 const SkImage_Lazy* img,
286 GrImageTexGenPolicy texGenPolicy,
287 skgpu::Mipmapped mipmapped) {
288 // Values representing the various texture lock paths we can take. Used for logging the path
289 // taken to a histogram.
290 enum LockTexturePath {
291 kFailure_LockTexturePath,
292 kPreExisting_LockTexturePath,
293 kNative_LockTexturePath,
294 kCompressed_LockTexturePath, // Deprecated
295 kYUV_LockTexturePath,
296 kRGBA_LockTexturePath,
297 };
298
299 enum { kLockTexturePathCount = kRGBA_LockTexturePath + 1 };
300
302 if (texGenPolicy == GrImageTexGenPolicy::kDraw) {
304 }
305
306 const GrCaps* caps = rContext->priv().caps();
307 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
308
309 auto installKey = [&](const GrSurfaceProxyView& view) {
310 SkASSERT(view && view.asTextureProxy());
311 if (key.isValid()) {
312 auto listener = GrMakeUniqueKeyInvalidationListener(&key, rContext->priv().contextID());
313 img->addUniqueIDListener(std::move(listener));
314 proxyProvider->assignUniqueKeyToProxy(key, view.asTextureProxy());
315 }
316 };
317
318 auto ct = ColorTypeOfLockTextureProxy(caps, img->colorType());
319
320 // 1. Check the cache for a pre-existing one.
321 if (key.isValid()) {
322 auto proxy = proxyProvider->findOrCreateProxyByUniqueKey(key);
323 if (proxy) {
324 skgpu::Swizzle swizzle = caps->getReadSwizzle(proxy->backendFormat(), ct);
325 GrSurfaceOrigin origin = get_origin(img);
326 GrSurfaceProxyView view(std::move(proxy), origin, swizzle);
327 if (mipmapped == skgpu::Mipmapped::kNo ||
329 return view;
330 } else {
331 // We need a mipped proxy, but we found a cached proxy that wasn't mipped. Thus we
332 // generate a new mipped surface and copy the original proxy into the base layer. We
333 // will then let the gpu generate the rest of the mips.
334 auto mippedView = GrCopyBaseMipMapToView(rContext, view);
335 if (!mippedView) {
336 // We failed to make a mipped proxy with the base copied into it. This could
337 // have been from failure to make the proxy or failure to do the copy. Thus we
338 // will fall back to just using the non mipped proxy; See skbug.com/7094.
339 return view;
340 }
341 proxyProvider->removeUniqueKeyFromProxy(view.asTextureProxy());
342 installKey(mippedView);
343 return mippedView;
344 }
345 }
346 }
347
348 // 2. Ask the generator to natively create one (if it knows how)
349 {
351 if (auto view = generate_picture_texture(rContext,
352 static_cast<const SkImage_Picture*>(img),
353 mipmapped,
354 texGenPolicy)) {
355 installKey(view);
356 return view;
357 }
358 } else if (img->generator()->isTextureGenerator()) {
359 auto sharedGenerator = img->generator();
360 SkAutoMutexExclusive mutex(sharedGenerator->fMutex);
361 auto textureGen = static_cast<GrTextureGenerator*>(sharedGenerator->fGenerator.get());
362 if (auto view = textureGen->generateTexture(rContext,
363 img->imageInfo(),
364 mipmapped,
365 texGenPolicy)) {
366 installKey(view);
367 return view;
368 }
369 }
370 }
371
372 // 3. Ask the generator to return YUV planes, which the GPU can convert. If we will be mipping
373 // the texture we skip this step so the CPU generate non-planar MIP maps for us.
374 if (mipmapped == skgpu::Mipmapped::kNo &&
375 !rContext->priv().options().fDisableGpuYUVConversion) {
376 // TODO: Update to create the mipped surface in the textureProxyViewFromPlanes generator and
377 // draw the base layer directly into the mipped surface.
381 auto view = texture_proxy_view_from_planes(rContext, img, budgeted);
382 if (view) {
383 installKey(view);
384 return view;
385 }
386 }
387
388 // 4. Ask the generator to return a bitmap, which the GPU can convert.
389 auto hint = texGenPolicy == GrImageTexGenPolicy::kDraw ? SkImage::CachingHint::kAllow_CachingHint
390 : SkImage::CachingHint::kDisallow_CachingHint;
391 if (SkBitmap bitmap; img->getROPixels(nullptr, &bitmap, hint)) {
392 // We always make an uncached bitmap here because we will cache it based on passed in policy
393 // with *our* key, not a key derived from bitmap. We're just making the proxy here.
394 auto budgeted = texGenPolicy == GrImageTexGenPolicy::kNew_Uncached_Unbudgeted
397 auto view = std::get<0>(GrMakeUncachedBitmapProxyView(rContext,
398 bitmap,
399 mipmapped,
401 budgeted));
402 if (view) {
403 installKey(view);
404 return view;
405 }
406 }
407
408 return {};
409}
410
411static std::tuple<GrSurfaceProxyView, GrColorType> lazy_as_view(GrRecordingContext* context,
412 const SkImage_Lazy* img,
413 skgpu::Mipmapped mipmapped,
415 GrColorType ct = ColorTypeOfLockTextureProxy(context->priv().caps(), img->colorType());
416 return {LockTextureProxyView(context, img, policy, mipmapped), ct};
417}
418
419std::tuple<GrSurfaceProxyView, GrColorType> AsView(GrRecordingContext* rContext,
420 const SkImage* img,
421 skgpu::Mipmapped mipmapped,
423 SkASSERT(img);
424 if (!rContext) {
425 return {};
426 }
427 if (!rContext->priv().caps()->mipmapSupport() || img->dimensions().area() <= 1) {
428 mipmapped = skgpu::Mipmapped::kNo;
429 }
430
431 auto ib = static_cast<const SkImage_Base*>(img);
432 if (ib->type() == SkImage_Base::Type::kRaster) {
434 rContext, static_cast<const SkImage_Raster*>(ib), mipmapped, policy);
435 } else if (ib->type() == SkImage_Base::Type::kRasterPinnable) {
436 auto rp = static_cast<const SkImage_RasterPinnable*>(img);
437 return rp->asView(rContext, mipmapped, policy);
438 } else if (ib->isGaneshBacked()) {
439 auto gb = static_cast<const SkImage_GaneshBase*>(img);
440 return gb->asView(rContext, mipmapped, policy);
441 } else if (ib->isLazyGenerated()) {
442 return lazy_as_view(rContext, static_cast<const SkImage_Lazy*>(ib), mipmapped, policy);
443 }
444
445 SkDEBUGFAIL("Unsupported image type to make a View");
446 return {};
447}
448
449static std::unique_ptr<GrFragmentProcessor> make_fp_from_view(GrRecordingContext* rContext,
451 SkAlphaType at,
453 const SkTileMode tileModes[2],
454 const SkMatrix& m,
455 const SkRect* subset,
456 const SkRect* domain) {
457 if (!view) {
458 return nullptr;
459 }
460 const GrCaps& caps = *rContext->priv().caps();
461 auto wmx = SkTileModeToWrapMode(tileModes[0]);
462 auto wmy = SkTileModeToWrapMode(tileModes[1]);
463 if (sampling.useCubic) {
464 if (subset) {
465 if (domain) {
466 return GrBicubicEffect::MakeSubset(std::move(view),
467 at,
468 m,
469 wmx,
470 wmy,
471 *subset,
472 *domain,
475 *rContext->priv().caps());
476 }
477 return GrBicubicEffect::MakeSubset(std::move(view),
478 at,
479 m,
480 wmx,
481 wmy,
482 *subset,
485 *rContext->priv().caps());
486 }
487 return GrBicubicEffect::Make(std::move(view),
488 at,
489 m,
490 wmx,
491 wmy,
494 *rContext->priv().caps());
495 }
496 if (sampling.isAniso()) {
497 if (!rContext->priv().caps()->anisoSupport()) {
498 // Fallback to linear
500 }
501 } else if (view.mipmapped() == skgpu::Mipmapped::kNo) {
503 }
504 GrSamplerState sampler;
505 if (sampling.isAniso()) {
506 sampler = GrSamplerState::Aniso(wmx, wmy, sampling.maxAniso, view.mipmapped());
507 } else {
508 sampler = GrSamplerState(wmx, wmy, sampling.filter, sampling.mipmap);
509 }
510 if (subset) {
511 if (domain) {
513 std::move(view), at, m, sampler, *subset, *domain, caps);
514 }
515 return GrTextureEffect::MakeSubset(std::move(view), at, m, sampler, *subset, caps);
516 } else {
517 return GrTextureEffect::Make(std::move(view), at, m, sampler, caps);
518 }
519}
520
521std::unique_ptr<GrFragmentProcessor> raster_as_fp(GrRecordingContext* rContext,
522 const SkImage_Raster* img,
524 const SkTileMode tileModes[2],
525 const SkMatrix& m,
526 const SkRect* subset,
527 const SkRect* domain) {
528 auto mm =
530 return make_fp_from_view(rContext,
531 std::get<0>(AsView(rContext, img, mm)),
532 img->alphaType(),
533 sampling,
534 tileModes,
535 m,
536 subset,
537 domain);
538}
539
540std::unique_ptr<GrFragmentProcessor> AsFragmentProcessor(GrRecordingContext* rContext,
541 const SkImage* img,
543 const SkTileMode tileModes[2],
544 const SkMatrix& m,
545 const SkRect* subset,
546 const SkRect* domain) {
547 if (!rContext) {
548 return {};
549 }
551 return {};
552 }
554 (!rContext->priv().caps()->mipmapSupport() || img->dimensions().area() <= 1)) {
556 }
557
558 auto ib = static_cast<const SkImage_Base*>(img);
559 if (ib->isRasterBacked()) {
560 return raster_as_fp(rContext,
561 static_cast<const SkImage_Raster*>(ib),
562 sampling,
563 tileModes,
564 m,
565 subset,
566 domain);
567 } else if (ib->isGaneshBacked()) {
568 auto gb = static_cast<const SkImage_GaneshBase*>(img);
569 return gb->asFragmentProcessor(rContext, sampling, tileModes, m, subset, domain);
570 } else if (ib->isLazyGenerated()) {
571 // TODO: If the CPU data is extracted as planes return a FP that reconstructs the image from
572 // the planes.
574 return MakeFragmentProcessorFromView(rContext,
575 std::get<0>(AsView(rContext, img, mm)),
576 img->alphaType(),
577 sampling,
578 tileModes,
579 m,
580 subset,
581 domain);
582 }
583
584 SkDEBUGFAIL("Unsupported image type to make a FragmentProcessor");
585 return {};
586}
587
588std::unique_ptr<GrFragmentProcessor> MakeFragmentProcessorFromView(
589 GrRecordingContext* rContext,
591 SkAlphaType at,
593 const SkTileMode tileModes[2],
594 const SkMatrix& m,
595 const SkRect* subset,
596 const SkRect* domain) {
597 if (!view) {
598 return nullptr;
599 }
600 const GrCaps& caps = *rContext->priv().caps();
601 auto wmx = SkTileModeToWrapMode(tileModes[0]);
602 auto wmy = SkTileModeToWrapMode(tileModes[1]);
603 if (sampling.useCubic) {
604 if (subset) {
605 if (domain) {
606 return GrBicubicEffect::MakeSubset(std::move(view),
607 at,
608 m,
609 wmx,
610 wmy,
611 *subset,
612 *domain,
615 *rContext->priv().caps());
616 }
617 return GrBicubicEffect::MakeSubset(std::move(view),
618 at,
619 m,
620 wmx,
621 wmy,
622 *subset,
625 *rContext->priv().caps());
626 }
627 return GrBicubicEffect::Make(std::move(view),
628 at,
629 m,
630 wmx,
631 wmy,
634 *rContext->priv().caps());
635 }
636 if (sampling.isAniso()) {
637 if (!rContext->priv().caps()->anisoSupport()) {
638 // Fallback to linear
640 }
641 } else if (view.mipmapped() == skgpu::Mipmapped::kNo) {
643 }
644 GrSamplerState sampler;
645 if (sampling.isAniso()) {
646 sampler = GrSamplerState::Aniso(wmx, wmy, sampling.maxAniso, view.mipmapped());
647 } else {
648 sampler = GrSamplerState(wmx, wmy, sampling.filter, sampling.mipmap);
649 }
650 if (subset) {
651 if (domain) {
652 return GrTextureEffect::MakeSubset(std::move(view),
653 at,
654 m,
655 sampler,
656 *subset,
657 *domain,
658 caps);
659 }
660 return GrTextureEffect::MakeSubset(std::move(view),
661 at,
662 m,
663 sampler,
664 *subset,
665 caps);
666 } else {
667 return GrTextureEffect::Make(std::move(view), at, m, sampler, caps);
668 }
669}
670
673 uint32_t imageUniqueID) {
674 SkASSERT(rContext);
675 SkASSERT(imageUniqueID != SK_InvalidUniqueID);
676
677 if (!view || view.proxy()->asTextureProxy()->mipmapped() == skgpu::Mipmapped::kYes) {
678 return view;
679 }
680 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
681
682 skgpu::UniqueKey baseKey;
683 GrMakeKeyFromImageID(&baseKey, imageUniqueID, SkIRect::MakeSize(view.dimensions()));
684 SkASSERT(baseKey.isValid());
685 skgpu::UniqueKey mipmappedKey;
686 static const skgpu::UniqueKey::Domain kMipmappedDomain = skgpu::UniqueKey::GenerateDomain();
687 { // No extra values beyond the domain are required. Must name the var to please
688 // clang-tidy.
689 skgpu::UniqueKey::Builder b(&mipmappedKey, baseKey, kMipmappedDomain, 0);
690 }
691 SkASSERT(mipmappedKey.isValid());
692 if (sk_sp<GrTextureProxy> cachedMippedView =
693 proxyProvider->findOrCreateProxyByUniqueKey(mipmappedKey)) {
694 return {std::move(cachedMippedView), view.origin(), view.swizzle()};
695 }
696
697 auto copy = GrCopyBaseMipMapToView(rContext, view);
698 if (!copy) {
699 return view;
700 }
701 // TODO: If we move listeners up from SkImage_Lazy to SkImage_Base then add one here.
702 proxyProvider->assignUniqueKeyToProxy(mipmappedKey, copy.asTextureProxy());
703 return copy;
704}
705
707
710 const auto isValid = [&context](DataType dt, int n) {
712 GrRenderable::kNo).isValid();
713 };
714 for (int n = 1; n <= 4; ++n) {
715 if (isValid(DataType::kUnorm8, n)) {
716 dataTypes.enableDataType(DataType::kUnorm8, n);
717 }
718 if (isValid(DataType::kUnorm16, n)) {
720 }
721 if (isValid(DataType::kFloat16, n)) {
723 }
724 if (isValid(DataType::kUnorm10_Unorm2, n)) {
726 }
727 }
728 return dataTypes;
729}
730
731} // namespace skgpu::ganesh
732
733namespace skif {
734
735namespace {
736
737class GaneshBackend :
738 public Backend,
739#if defined(SK_USE_LEGACY_BLUR_GANESH)
741#else
742 private SkShaderBlurAlgorithm,
743#endif
744 private SkBlurEngine {
745public:
746
747 GaneshBackend(sk_sp<GrRecordingContext> context,
748 GrSurfaceOrigin origin,
749 const SkSurfaceProps& surfaceProps,
751 : Backend(SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize),
752 surfaceProps, colorType)
753 , fContext(std::move(context))
754 , fOrigin(origin) {}
755
756 // Backend
757 sk_sp<SkDevice> makeDevice(SkISize size,
758 sk_sp<SkColorSpace> colorSpace,
759 const SkSurfaceProps* props) const override {
761 this->colorType(),
763 std::move(colorSpace));
764
765 return fContext->priv().createDevice(skgpu::Budgeted::kYes,
766 imageInfo,
768 1,
771 fOrigin,
772 props ? *props : this->surfaceProps(),
774 }
775
776 sk_sp<SkSpecialImage> makeImage(const SkIRect& subset, sk_sp<SkImage> image) const override {
778 fContext.get(), subset, image, this->surfaceProps());
779 }
780
781 sk_sp<SkImage> getCachedBitmap(const SkBitmap& data) const override {
782 // This uses the thread safe cache (instead of GrMakeCachedBitmapProxyView) so that image
783 // filters can be evaluated on other threads with DDLs.
784 auto threadSafeCache = fContext->priv().threadSafeCache();
785
787 SkIRect subset = SkIRect::MakePtSize(data.pixelRefOrigin(), data.dimensions());
788 GrMakeKeyFromImageID(&key, data.getGenerationID(), subset);
789
790 auto view = threadSafeCache->find(key);
791 if (!view) {
793 if (!view) {
794 return nullptr;
795 }
796 threadSafeCache->add(key, view);
797 }
798
799 return sk_make_sp<SkImage_Ganesh>(fContext,
800 data.getGenerationID(),
801 std::move(view),
802 data.info().colorInfo());
803 }
804
805 const SkBlurEngine* getBlurEngine() const override { return this; }
806
807 // SkBlurEngine
808 const SkBlurEngine::Algorithm* findAlgorithm(SkSize sigma,
809 SkColorType colorType) const override {
810 // GrBlurUtils supports all tile modes and color types
811 return this;
812 }
813
814#if defined(SK_USE_LEGACY_BLUR_GANESH)
815 // NOTE: When SK_USE_LEGACY_BLUR_GANESH is defined, `useLegacyFilterResultBlur()` returns true,
816 // so FilterResult::blur() will resolve all tiling in the original image space before calling
817 // into this function that routes to GrBlurUtils::GaussianBlur to perform the rescaling and
818 // blurring. It is possible ot restore original GrBlurUtils performance by just having
819 // `useLegacyFilterResultBlur()` return false but still reporting a max sigma of infinity and
820 // advertising support for all tile modes.
821 //
822 // Since all clients are currently rebased on the intermediate "legacy" blur approach, the ideal
823 // step would be to just migrate them to the SkShaderBlurAlgorithm variant instead of first
824 // going back to pure GrBlurUtils. But if needed for cherry-picking to old releases, the
825 // original GrBlurUtils behavior can be achieved quikly.
826
827 // SkBlurEngine::Algorithm
828 float maxSigma() const override {
829 // GrBlurUtils handles resizing at the moment
830 return SK_ScalarInfinity;
831 }
832
833 bool supportsOnlyDecalTiling() const override { return false; }
834
835 sk_sp<SkSpecialImage> blur(SkSize sigma,
837 const SkIRect& srcRect,
838 SkTileMode tileMode,
839 const SkIRect& dstRect) const override {
840 GrSurfaceProxyView inputView = SkSpecialImages::AsView(fContext.get(), input);
841 if (!inputView.proxy()) {
842 return nullptr;
843 }
844 SkASSERT(inputView.asTextureProxy());
845
846 // Update srcRect and dstRect to be relative to the underlying texture proxy of 'input'.
847 auto proxyOffset = input->subset().topLeft() - srcRect.topLeft();
848 auto sdc = GrBlurUtils::GaussianBlur(
849 fContext.get(),
850 std::move(inputView),
852 input->alphaType(),
853 sk_ref_sp(input->getColorSpace()),
854 dstRect.makeOffset(proxyOffset),
855 srcRect.makeOffset(proxyOffset),
856 sigma.width(),
857 sigma.height(),
858 tileMode);
859 if (!sdc) {
860 return nullptr;
861 }
862
864 SkIRect::MakeSize(dstRect.size()),
866 sdc->readSurfaceView(),
867 sdc->colorInfo(),
868 this->surfaceProps());
869 }
870#else
871 bool useLegacyFilterResultBlur() const override { return false; }
872
873 // SkShaderBlurAlgorithm
874 sk_sp<SkDevice> makeDevice(const SkImageInfo& imageInfo) const override {
875 return fContext->priv().createDevice(skgpu::Budgeted::kYes,
876 imageInfo,
878 1,
881 fOrigin,
882 this->surfaceProps(),
884 }
885
886#endif
887
888private:
890 GrSurfaceOrigin fOrigin;
891};
892
893} // anonymous namespace
894
896 GrSurfaceOrigin origin,
897 const SkSurfaceProps& surfaceProps,
899 SkASSERT(context);
900 return sk_make_sp<GaneshBackend>(std::move(context), origin, surfaceProps, colorType);
901}
902
903} // namespace skif
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
GrColorType
Definition: GrTypesPriv.h:540
static constexpr GrColorType SkColorTypeToGrColorType(SkColorType ct)
Definition: GrTypesPriv.h:629
GrSurfaceOrigin
Definition: GrTypes.h:147
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
static sk_sp< Effect > Create()
Definition: RefCntTest.cpp:117
SkAlphaType
Definition: SkAlphaType.h:26
@ kOpaque_SkAlphaType
pixel is opaque
Definition: SkAlphaType.h:28
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkBackingFit
Definition: SkBackingFit.h:16
SkColorType
Definition: SkColorType.h:19
GrSurfaceProxyView GrCopyBaseMipMapToView(GrRecordingContext *context, GrSurfaceProxyView src, skgpu::Budgeted budgeted)
Definition: SkGr.cpp:136
void GrMakeKeyFromImageID(skgpu::UniqueKey *key, uint32_t imageID, const SkIRect &imageBounds)
Definition: SkGr.cpp:60
std::tuple< GrSurfaceProxyView, GrColorType > GrMakeUncachedBitmapProxyView(GrRecordingContext *rContext, const SkBitmap &bitmap, skgpu::Mipmapped mipmapped, SkBackingFit fit, skgpu::Budgeted budgeted)
Definition: SkGr.cpp:253
sk_sp< SkIDChangeListener > GrMakeUniqueKeyInvalidationListener(skgpu::UniqueKey *key, uint32_t contextID)
Definition: SkGr.cpp:75
std::tuple< GrSurfaceProxyView, GrColorType > GrMakeCachedBitmapProxyView(GrRecordingContext *rContext, const SkBitmap &bitmap, std::string_view label, skgpu::Mipmapped mipmapped)
Definition: SkGr.cpp:188
GrImageTexGenPolicy
Definition: SkGr.h:141
static constexpr GrSamplerState::WrapMode SkTileModeToWrapMode(SkTileMode tileMode)
Definition: SkGr.h:77
static bool GrValidCubicResampler(SkCubicResampler cubic)
Definition: SkGr.h:211
static void releaseProc(const void *ptr, void *context)
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
static T * SkRef(T *obj)
Definition: SkRefCnt.h:132
const Context & fContext
#define SK_ScalarInfinity
Definition: SkScalar.h:26
@ kNeedNewImageUniqueID_SpecialImage
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
Definition: SkSwizzler.cpp:31
SkTileMode
Definition: SkTileMode.h:13
static constexpr uint32_t SK_InvalidUniqueID
Definition: SkTypes.h:196
const GrContextOptions & options() const
uint32_t contextID() const
const GrCaps * caps() const
static std::unique_ptr< GrFragmentProcessor > Make(GrSurfaceProxyView view, SkAlphaType, const SkMatrix &, SkCubicResampler, Direction)
static std::unique_ptr< GrFragmentProcessor > MakeSubset(GrSurfaceProxyView view, SkAlphaType, const SkMatrix &, const GrSamplerState::WrapMode wrapX, const GrSamplerState::WrapMode wrapY, const SkRect &subset, SkCubicResampler, Direction, const GrCaps &)
Definition: GrCaps.h:57
bool mipmapSupport() const
Definition: GrCaps.h:72
bool anisoSupport() const
Definition: GrCaps.h:74
GrBackendFormat getDefaultBackendFormat(GrColorType, GrRenderable) const
Definition: GrCaps.cpp:400
skgpu::Swizzle getReadSwizzle(const GrBackendFormat &format, GrColorType colorType) const
Definition: GrCaps.cpp:443
static std::unique_ptr< GrFragmentProcessor > Make(std::unique_ptr< GrFragmentProcessor > child, SkColorSpace *src, SkAlphaType srcAT, SkColorSpace *dst, SkAlphaType dstAT)
SK_API GrBackendFormat defaultBackendFormat(SkColorType, GrRenderable) const
void removeUniqueKeyFromProxy(GrTextureProxy *)
bool assignUniqueKeyToProxy(const skgpu::UniqueKey &, GrTextureProxy *)
sk_sp< GrTextureProxy > findOrCreateProxyByUniqueKey(const skgpu::UniqueKey &, UseAllocator=UseAllocator::kYes)
GrProxyProvider * proxyProvider()
std::unique_ptr< skgpu::ganesh::SurfaceFillContext > makeSFC(GrImageInfo, std::string_view label, SkBackingFit=SkBackingFit::kExact, int sampleCount=1, skgpu::Mipmapped=skgpu::Mipmapped::kNo, skgpu::Protected=skgpu::Protected::kNo, GrSurfaceOrigin=kTopLeft_GrSurfaceOrigin, skgpu::Budgeted=skgpu::Budgeted::kYes)
GrRecordingContextPriv priv()
static constexpr GrSamplerState Aniso(WrapMode wrapX, WrapMode wrapY, int maxAniso, skgpu::Mipmapped viewIsMipped)
skgpu::Swizzle swizzle() const
skgpu::Mipmapped mipmapped() const
GrTextureProxy * asTextureProxy() const
SkISize dimensions() const
GrSurfaceOrigin origin() const
GrSurfaceProxy * proxy() const
static GrSurfaceProxyView Copy(GrRecordingContext *context, GrSurfaceProxyView src, skgpu::Mipmapped mipmapped, SkIRect srcRect, SkBackingFit fit, skgpu::Budgeted budgeted, std::string_view label)
virtual GrTextureProxy * asTextureProxy()
static std::unique_ptr< GrFragmentProcessor > MakeSubset(GrSurfaceProxyView, SkAlphaType, const SkMatrix &, GrSamplerState, const SkRect &subset, const GrCaps &caps, const float border[4]=kDefaultBorder, bool alwaysUseShaderTileMode=false)
static std::unique_ptr< GrFragmentProcessor > Make(GrSurfaceProxyView, SkAlphaType, const SkMatrix &=SkMatrix::I(), GrSamplerState::Filter=GrSamplerState::Filter::kNearest, GrSamplerState::MipmapMode mipmapMode=GrSamplerState::MipmapMode::kNone)
skgpu::Mipmapped mipmapped() const
static std::unique_ptr< GrFragmentProcessor > Make(const GrYUVATextureProxies &yuvaProxies, GrSamplerState samplerState, const GrCaps &, const SkMatrix &localMatrix=SkMatrix::I(), const SkRect *subset=nullptr, const SkRect *domain=nullptr)
const SkImageInfo & getInfo() const
std::unique_ptr< SkImageGenerator > fGenerator
Definition: SkImage_Lazy.h:117
bool isTextureGenerator()
virtual std::tuple< GrSurfaceProxyView, GrColorType > asView(GrRecordingContext *, skgpu::Mipmapped, GrImageTexGenPolicy) const =0
virtual std::unique_ptr< GrFragmentProcessor > asFragmentProcessor(GrRecordingContext *, SkSamplingOptions, const SkTileMode[2], const SkMatrix &, const SkRect *, const SkRect *) const =0
bool getROPixels(GrDirectContext *, SkBitmap *, CachingHint) const override
void addUniqueIDListener(sk_sp< SkIDChangeListener >) const
sk_sp< SharedGenerator > generator() const
SkImage_Base::Type type() const override
Definition: SkImage_Lazy.h:73
sk_sp< SkCachedData > getPlanes(const SkYUVAPixmapInfo::SupportedDataTypes &supportedDataTypes, SkYUVAPixmaps *pixmaps) const
const SkSurfaceProps * props() const
void replay(SkCanvas *) const
std::tuple< GrSurfaceProxyView, GrColorType > asView(GrRecordingContext *, skgpu::Mipmapped, GrImageTexGenPolicy) const
SkBitmap bitmap() const
const SkImageInfo & imageInfo() const
Definition: SkImage.h:279
SkColorSpace * colorSpace() const
Definition: SkImage.cpp:156
SkISize dimensions() const
Definition: SkImage.h:297
uint32_t uniqueID() const
Definition: SkImage.h:311
SkAlphaType alphaType() const
Definition: SkImage.cpp:154
SkColorType colorType() const
Definition: SkImage.cpp:152
bool hasMipmaps() const
Definition: SkImage.cpp:292
size_t rowBytes() const
Definition: SkPixmap.h:145
const SkImageInfo & info() const
Definition: SkPixmap.h:135
void * writable_addr() const
Definition: SkPixmap.h:483
SkISize dimensions() const
Definition: SkPixmap.h:171
static SkSamplingOptions AnisoFallback(bool imageIsMipped)
SkAlphaType alphaType() const
SkColorSpace * getColorSpace() const
const SkIRect & subset() const
SkColorType colorType() const
static constexpr int kMaxPlanes
Definition: SkYUVAInfo.h:98
void enableDataType(DataType, int numChannels)
@ kUnorm10_Unorm2
10 bit unorm for Y, U, and V. 2 bit unorm for alpha (if present).
@ kUnorm8
8 bit unsigned normalized
@ kUnorm16
16 bit unsigned normalized
@ kFloat16
16 bit (half) floating point
static constexpr SkColorType DefaultColorTypeForDataType(DataType dataType, int numChannels)
const SkYUVAInfo & yuvaInfo() const
const SkPixmap & plane(int i) const
int numPlanes() const
T * get() const
Definition: SkRefCnt.h:303
bool isValid() const
Definition: ResourceKey.h:55
static Domain GenerateDomain()
Definition: ResourceKey.cpp:27
VkSurfaceKHR surface
Definition: main.cc:49
static bool b
uint32_t uint32_t * format
std::unique_ptr< skgpu::ganesh::SurfaceDrawContext > GaussianBlur(GrRecordingContext *rContext, GrSurfaceProxyView srcView, GrColorType srcColorType, SkAlphaType srcAlphaType, sk_sp< SkColorSpace > colorSpace, SkIRect dstBounds, SkIRect srcBounds, float sigmaX, float sigmaY, SkTileMode mode, SkBackingFit fit)
sk_sp< const SkImage > image
Definition: SkRecords.h:269
SkSamplingOptions sampling
Definition: SkRecords.h:337
GrSurfaceProxyView AsView(GrRecordingContext *context, const SkSpecialImage *img)
sk_sp< SkSpecialImage > MakeFromTextureImage(GrRecordingContext *rContext, const SkIRect &subset, sk_sp< SkImage > image, const SkSurfaceProps &props)
sk_sp< SkSpecialImage > MakeDeferredFromGpu(GrRecordingContext *context, const SkIRect &subset, uint32_t uniqueID, GrSurfaceProxyView view, const GrColorInfo &colorInfo, const SkSurfaceProps &props)
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
Definition: bitmap.py:1
Definition: copy.py:1
const uint32_t fp
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 keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network policy
Definition: switches.h:248
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 keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
const myers::Point & get< 0 >(const myers::Segment &s)
Definition: Myers.h:80
std::unique_ptr< GrFragmentProcessor > AsFragmentProcessor(GrRecordingContext *rContext, const SkImage *img, SkSamplingOptions sampling, const SkTileMode tileModes[2], const SkMatrix &m, const SkRect *subset, const SkRect *domain)
std::tuple< GrSurfaceProxyView, GrColorType > RasterAsView(GrRecordingContext *rContext, const SkImage_Raster *raster, skgpu::Mipmapped mipmapped, GrImageTexGenPolicy policy)
static std::unique_ptr< GrFragmentProcessor > make_fp_from_view(GrRecordingContext *rContext, GrSurfaceProxyView view, SkAlphaType at, SkSamplingOptions sampling, const SkTileMode tileModes[2], const SkMatrix &m, const SkRect *subset, const SkRect *domain)
GrColorType ColorTypeOfLockTextureProxy(const GrCaps *caps, SkColorType sct)
GrSurfaceProxyView FindOrMakeCachedMipmappedView(GrRecordingContext *rContext, GrSurfaceProxyView view, uint32_t imageUniqueID)
static GrSurfaceOrigin get_origin(const SkImage_Lazy *img)
GrSurfaceProxyView LockTextureProxyView(GrRecordingContext *rContext, const SkImage_Lazy *img, GrImageTexGenPolicy texGenPolicy, skgpu::Mipmapped mipmapped)
std::unique_ptr< GrFragmentProcessor > raster_as_fp(GrRecordingContext *rContext, const SkImage_Raster *img, SkSamplingOptions sampling, const SkTileMode tileModes[2], const SkMatrix &m, const SkRect *subset, const SkRect *domain)
GrSurfaceProxyView CopyView(GrRecordingContext *context, GrSurfaceProxyView src, skgpu::Mipmapped mipmapped, GrImageTexGenPolicy policy, std::string_view label)
std::tuple< GrSurfaceProxyView, GrColorType > AsView(GrRecordingContext *rContext, const SkImage *img, skgpu::Mipmapped mipmapped, GrImageTexGenPolicy policy)
static GrSurfaceProxyView texture_proxy_view_from_planes(GrRecordingContext *ctx, const SkImage_Lazy *img, skgpu::Budgeted budgeted)
static std::tuple< GrSurfaceProxyView, GrColorType > lazy_as_view(GrRecordingContext *context, const SkImage_Lazy *img, skgpu::Mipmapped mipmapped, GrImageTexGenPolicy policy)
std::unique_ptr< GrFragmentProcessor > MakeFragmentProcessorFromView(GrRecordingContext *rContext, GrSurfaceProxyView view, SkAlphaType at, SkSamplingOptions sampling, const SkTileMode tileModes[2], const SkMatrix &m, const SkRect *subset, const SkRect *domain)
SkYUVAPixmapInfo::SupportedDataTypes SupportedTextureFormats(const GrImageContext &context)
static GrSurfaceProxyView generate_picture_texture(GrRecordingContext *ctx, const SkImage_Picture *img, skgpu::Mipmapped mipmapped, GrImageTexGenPolicy texGenPolicy)
Budgeted
Definition: GpuTypes.h:35
Mipmapped
Definition: GpuTypes.h:53
SkSamplingOptions(SkFilterMode::kLinear))
Definition: SkDevice.h:63
sk_sp< Backend > MakeGaneshBackend(sk_sp< GrRecordingContext > context, GrSurfaceOrigin origin, const SkSurfaceProps &surfaceProps, SkColorType colorType)
Definition: ref_ptr.h:256
Definition: SkRect.h:32
constexpr SkISize size() const
Definition: SkRect.h:172
static constexpr SkIRect MakeSize(const SkISize &size)
Definition: SkRect.h:66
constexpr SkIRect makeOffset(int32_t dx, int32_t dy) const
Definition: SkRect.h:300
constexpr SkIPoint topLeft() const
Definition: SkRect.h:151
static constexpr SkIRect MakePtSize(SkIPoint pt, SkISize size)
Definition: SkRect.h:78
Definition: SkSize.h:16
constexpr int64_t area() const
Definition: SkSize.h:39
SkColorSpace * colorSpace() const
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
const SkCubicResampler cubic
const SkFilterMode filter
const SkMipmapMode mipmap
Definition: SkSize.h:52
SkScalar width() const
Definition: SkSize.h:76
SkScalar height() const
Definition: SkSize.h:77
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63