Flutter Engine
The Flutter Engine
Functions
SkGr.cpp File Reference
#include "src/gpu/ganesh/SkGr.h"
#include "include/core/SkAlphaType.h"
#include "include/core/SkBitmap.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkData.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPixelRef.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkSize.h"
#include "include/core/SkSurfaceProps.h"
#include "include/effects/SkRuntimeEffect.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrRecordingContext.h"
#include "include/gpu/GrTypes.h"
#include "include/private/SkIDChangeListener.h"
#include "include/private/base/SkTPin.h"
#include "include/private/gpu/ganesh/GrTypesPriv.h"
#include "src/core/SkBlenderBase.h"
#include "src/core/SkMessageBus.h"
#include "src/core/SkPaintPriv.h"
#include "src/core/SkRuntimeEffectPriv.h"
#include "src/gpu/DitherUtils.h"
#include "src/gpu/ResourceKey.h"
#include "src/gpu/Swizzle.h"
#include "src/gpu/ganesh/GrCaps.h"
#include "src/gpu/ganesh/GrColorInfo.h"
#include "src/gpu/ganesh/GrColorSpaceXform.h"
#include "src/gpu/ganesh/GrFPArgs.h"
#include "src/gpu/ganesh/GrFragmentProcessor.h"
#include "src/gpu/ganesh/GrFragmentProcessors.h"
#include "src/gpu/ganesh/GrPaint.h"
#include "src/gpu/ganesh/GrProxyProvider.h"
#include "src/gpu/ganesh/GrRecordingContextPriv.h"
#include "src/gpu/ganesh/GrSurfaceProxy.h"
#include "src/gpu/ganesh/GrSurfaceProxyView.h"
#include "src/gpu/ganesh/GrTextureProxy.h"
#include "src/gpu/ganesh/GrXferProcessor.h"
#include "src/gpu/ganesh/effects/GrSkSLFP.h"
#include "src/gpu/ganesh/effects/GrTextureEffect.h"
#include "src/shaders/SkShaderBase.h"
#include <optional>
#include <utility>

Go to the source code of this file.

Functions

void GrMakeKeyFromImageID (skgpu::UniqueKey *key, uint32_t imageID, const SkIRect &imageBounds)
 
sk_sp< SkIDChangeListenerGrMakeUniqueKeyInvalidationListener (skgpu::UniqueKey *key, uint32_t contextID)
 
sk_sp< GrSurfaceProxyGrCopyBaseMipMapToTextureProxy (GrRecordingContext *ctx, sk_sp< GrSurfaceProxy > baseProxy, GrSurfaceOrigin origin, std::string_view label, skgpu::Budgeted budgeted)
 
GrSurfaceProxyView GrCopyBaseMipMapToView (GrRecordingContext *context, GrSurfaceProxyView src, skgpu::Budgeted budgeted)
 
static skgpu::Mipmapped adjust_mipmapped (skgpu::Mipmapped mipmapped, const SkBitmap &bitmap, const GrCaps *caps)
 
static GrColorType choose_bmp_texture_colortype (const GrCaps *caps, const SkBitmap &bitmap)
 
static sk_sp< GrTextureProxymake_bmp_proxy (GrProxyProvider *proxyProvider, const SkBitmap &bitmap, GrColorType ct, skgpu::Mipmapped mipmapped, SkBackingFit fit, skgpu::Budgeted budgeted)
 
std::tuple< GrSurfaceProxyView, GrColorTypeGrMakeCachedBitmapProxyView (GrRecordingContext *rContext, const SkBitmap &bitmap, std::string_view label, skgpu::Mipmapped mipmapped)
 
std::tuple< GrSurfaceProxyView, GrColorTypeGrMakeUncachedBitmapProxyView (GrRecordingContext *rContext, const SkBitmap &bitmap, skgpu::Mipmapped mipmapped, SkBackingFit fit, skgpu::Budgeted budgeted)
 
SkPMColor4f SkColorToPMColor4f (SkColor c, const GrColorInfo &colorInfo)
 
SkColor4f SkColor4fPrepForDst (SkColor4f color, const GrColorInfo &colorInfo)
 
static bool blender_requires_shader (const SkBlender *blender)
 
static std::unique_ptr< GrFragmentProcessormake_dither_effect (GrRecordingContext *rContext, std::unique_ptr< GrFragmentProcessor > inputFP, float range, const GrCaps *caps)
 
static bool skpaint_to_grpaint_impl (GrRecordingContext *context, const GrColorInfo &dstColorInfo, const SkPaint &skPaint, const SkMatrix &ctm, std::optional< std::unique_ptr< GrFragmentProcessor > > shaderFP, SkBlender *primColorBlender, const SkSurfaceProps &surfaceProps, GrPaint *grPaint)
 
bool SkPaintToGrPaint (GrRecordingContext *context, const GrColorInfo &dstColorInfo, const SkPaint &skPaint, const SkMatrix &ctm, const SkSurfaceProps &surfaceProps, GrPaint *grPaint)
 
bool SkPaintToGrPaintReplaceShader (GrRecordingContext *context, const GrColorInfo &dstColorInfo, const SkPaint &skPaint, const SkMatrix &ctm, std::unique_ptr< GrFragmentProcessor > shaderFP, const SkSurfaceProps &surfaceProps, GrPaint *grPaint)
 
bool SkPaintToGrPaintWithBlend (GrRecordingContext *context, const GrColorInfo &dstColorInfo, const SkPaint &skPaint, const SkMatrix &ctm, SkBlender *primColorBlender, const SkSurfaceProps &surfaceProps, GrPaint *grPaint)
 

Function Documentation

◆ adjust_mipmapped()

static skgpu::Mipmapped adjust_mipmapped ( skgpu::Mipmapped  mipmapped,
const SkBitmap bitmap,
const GrCaps caps 
)
static

Definition at line 148 of file SkGr.cpp.

150 {
151 if (!caps->mipmapSupport() || bitmap.dimensions().area() <= 1) {
153 }
154 return mipmapped;
155}
bool mipmapSupport() const
Definition: GrCaps.h:72
Definition: bitmap.py:1

◆ blender_requires_shader()

static bool blender_requires_shader ( const SkBlender blender)
inlinestatic

Definition at line 292 of file SkGr.cpp.

292 {
293 SkASSERT(blender);
294 std::optional<SkBlendMode> mode = as_BB(blender)->asBlendMode();
295 return !mode.has_value() || *mode != SkBlendMode::kDst;
296}
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkBlenderBase * as_BB(SkBlender *blend)
Definition: SkBlenderBase.h:69
virtual std::optional< SkBlendMode > asBlendMode() const
Definition: SkBlenderBase.h:45
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

◆ choose_bmp_texture_colortype()

static GrColorType choose_bmp_texture_colortype ( const GrCaps caps,
const SkBitmap bitmap 
)
static

Definition at line 157 of file SkGr.cpp.

157 {
158 GrColorType ct = SkColorTypeToGrColorType(bitmap.info().colorType());
160 return ct;
161 }
163}
GrColorType
Definition: GrTypesPriv.h:540
static constexpr GrColorType SkColorTypeToGrColorType(SkColorType ct)
Definition: GrTypesPriv.h:629
bool isValid() const
GrBackendFormat getDefaultBackendFormat(GrColorType, GrRenderable) const
Definition: GrCaps.cpp:400

◆ GrCopyBaseMipMapToTextureProxy()

sk_sp< GrSurfaceProxy > GrCopyBaseMipMapToTextureProxy ( GrRecordingContext ctx,
sk_sp< GrSurfaceProxy baseProxy,
GrSurfaceOrigin  origin,
std::string_view  label,
skgpu::Budgeted  budgeted = skgpu::Budgeted::kYes 
)

Creates a new texture with mipmap levels and copies the baseProxy into the base layer.

Definition at line 107 of file SkGr.cpp.

111 {
112 SkASSERT(baseProxy);
113
114 // We don't allow this for promise proxies i.e. if they need mips they need to give them
115 // to us upfront.
116 if (baseProxy->isPromiseProxy()) {
117 return nullptr;
118 }
119 if (!ctx->priv().caps()->isFormatCopyable(baseProxy->backendFormat())) {
120 return nullptr;
121 }
122 auto copy = GrSurfaceProxy::Copy(ctx,
123 std::move(baseProxy),
124 origin,
127 budgeted,
128 label);
129 if (!copy) {
130 return nullptr;
131 }
132 SkASSERT(copy->asTextureProxy());
133 return copy;
134}
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
Definition: SkSwizzler.cpp:31
const GrCaps * caps() const
virtual bool isFormatCopyable(const GrBackendFormat &) const =0
GrRecordingContextPriv priv()
const GrBackendFormat & backendFormat() const
static sk_sp< GrSurfaceProxy > Copy(GrRecordingContext *, sk_sp< GrSurfaceProxy > src, GrSurfaceOrigin, skgpu::Mipmapped, SkIRect srcRect, SkBackingFit, skgpu::Budgeted, std::string_view label, RectsMustMatch=RectsMustMatch::kNo, sk_sp< GrRenderTask > *outTask=nullptr)
Definition: copy.py:1

◆ GrCopyBaseMipMapToView()

GrSurfaceProxyView GrCopyBaseMipMapToView ( GrRecordingContext context,
GrSurfaceProxyView  src,
skgpu::Budgeted  budgeted = skgpu::Budgeted::kYes 
)

Same as GrCopyBaseMipMapToTextureProxy but takes the src as a view and returns a view with same origin and swizzle as the src view.

Definition at line 136 of file SkGr.cpp.

138 {
139 auto origin = src.origin();
140 auto swizzle = src.swizzle();
141 auto proxy = src.refProxy();
143 context, proxy, origin, /*label=*/"CopyBaseMipMapToView", budgeted),
144 origin,
145 swizzle};
146}
sk_sp< GrSurfaceProxy > GrCopyBaseMipMapToTextureProxy(GrRecordingContext *ctx, sk_sp< GrSurfaceProxy > baseProxy, GrSurfaceOrigin origin, std::string_view label, skgpu::Budgeted budgeted)
Definition: SkGr.cpp:107

◆ GrMakeCachedBitmapProxyView()

std::tuple< GrSurfaceProxyView, GrColorType > GrMakeCachedBitmapProxyView ( GrRecordingContext rContext,
const SkBitmap bitmap,
std::string_view  label,
skgpu::Mipmapped  mipmapped 
)

Definition at line 188 of file SkGr.cpp.

192 {
193 if (!bitmap.peekPixels(nullptr)) {
194 return {};
195 }
196
197 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
198 const GrCaps* caps = rContext->priv().caps();
199
201 SkIPoint origin = bitmap.pixelRefOrigin();
202 SkIRect subset = SkIRect::MakePtSize(origin, bitmap.dimensions());
203 GrMakeKeyFromImageID(&key, bitmap.pixelRef()->getGenerationID(), subset);
204
205 mipmapped = adjust_mipmapped(mipmapped, bitmap, caps);
207
208 auto installKey = [&](GrTextureProxy* proxy) {
209 auto listener = GrMakeUniqueKeyInvalidationListener(&key, proxyProvider->contextID());
210 bitmap.pixelRef()->addGenIDChangeListener(std::move(listener));
211 proxyProvider->assignUniqueKeyToProxy(key, proxy);
212 };
213
215 if (!proxy) {
216 proxy = make_bmp_proxy(
217 proxyProvider, bitmap, ct, mipmapped, SkBackingFit::kExact, skgpu::Budgeted::kYes);
218 if (!proxy) {
219 return {};
220 }
221 SkASSERT(mipmapped == skgpu::Mipmapped::kNo ||
223 installKey(proxy.get());
224 }
225
226 skgpu::Swizzle swizzle = caps->getReadSwizzle(proxy->backendFormat(), ct);
227 if (mipmapped == skgpu::Mipmapped::kNo || proxy->mipmapped() == skgpu::Mipmapped::kYes) {
228 return {{std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle}, ct};
229 }
230
231 // We need a mipped proxy, but we found a proxy earlier that wasn't mipped. Thus we generate
232 // a new mipped surface and copy the original proxy into the base layer. We will then let
233 // the gpu generate the rest of the mips.
234 auto mippedProxy = GrCopyBaseMipMapToTextureProxy(
235 rContext, proxy, kTopLeft_GrSurfaceOrigin, /*label=*/"MakeCachedBitmapProxyView");
236 if (!mippedProxy) {
237 // We failed to make a mipped proxy with the base copied into it. This could have
238 // been from failure to make the proxy or failure to do the copy. Thus we will fall
239 // back to just using the non mipped proxy; See skbug.com/7094.
240 return {{std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle}, ct};
241 }
242 // In this case we are stealing the key from the original proxy which should only happen
243 // when we have just generated mipmaps for an originally unmipped proxy/texture. This
244 // means that all future uses of the key will access the mipmapped version. The texture
245 // backing the unmipped version will remain in the resource cache until the last texture
246 // proxy referencing it is deleted at which time it too will be deleted or recycled.
247 SkASSERT(proxy->getUniqueKey() == key);
248 proxyProvider->removeUniqueKeyFromProxy(proxy.get());
249 installKey(mippedProxy->asTextureProxy());
250 return {{std::move(mippedProxy), kTopLeft_GrSurfaceOrigin, swizzle}, ct};
251}
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
void GrMakeKeyFromImageID(skgpu::UniqueKey *key, uint32_t imageID, const SkIRect &imageBounds)
Definition: SkGr.cpp:60
static sk_sp< GrTextureProxy > make_bmp_proxy(GrProxyProvider *proxyProvider, const SkBitmap &bitmap, GrColorType ct, skgpu::Mipmapped mipmapped, SkBackingFit fit, skgpu::Budgeted budgeted)
Definition: SkGr.cpp:165
sk_sp< SkIDChangeListener > GrMakeUniqueKeyInvalidationListener(skgpu::UniqueKey *key, uint32_t contextID)
Definition: SkGr.cpp:75
static skgpu::Mipmapped adjust_mipmapped(skgpu::Mipmapped mipmapped, const SkBitmap &bitmap, const GrCaps *caps)
Definition: SkGr.cpp:148
static GrColorType choose_bmp_texture_colortype(const GrCaps *caps, const SkBitmap &bitmap)
Definition: SkGr.cpp:157
Definition: GrCaps.h:57
skgpu::Swizzle getReadSwizzle(const GrBackendFormat &format, GrColorType colorType) const
Definition: GrCaps.cpp:443
uint32_t contextID() const
void removeUniqueKeyFromProxy(GrTextureProxy *)
bool assignUniqueKeyToProxy(const skgpu::UniqueKey &, GrTextureProxy *)
sk_sp< GrTextureProxy > findOrCreateProxyByUniqueKey(const skgpu::UniqueKey &, UseAllocator=UseAllocator::kYes)
GrProxyProvider * proxyProvider()
const skgpu::UniqueKey & getUniqueKey() const override
skgpu::Mipmapped mipmapped() const
T * get() const
Definition: SkRefCnt.h:303
Definition: SkRect.h:32
static constexpr SkIRect MakePtSize(SkIPoint pt, SkISize size)
Definition: SkRect.h:78

◆ GrMakeKeyFromImageID()

void GrMakeKeyFromImageID ( skgpu::UniqueKey key,
uint32_t  imageID,
const SkIRect imageBounds 
)

Our key includes the offset, width, and height so that bitmaps created by extractSubset() are unique.

The imageID is in the shared namespace (see SkNextID::ImageID())

Definition at line 60 of file SkGr.cpp.

60 {
62 SkASSERT(imageID);
63 SkASSERT(!imageBounds.isEmpty());
64 static const skgpu::UniqueKey::Domain kImageIDDomain = skgpu::UniqueKey::GenerateDomain();
65 skgpu::UniqueKey::Builder builder(key, kImageIDDomain, 5, "Image");
66 builder[0] = imageID;
67 builder[1] = imageBounds.fLeft;
68 builder[2] = imageBounds.fTop;
69 builder[3] = imageBounds.fRight;
70 builder[4] = imageBounds.fBottom;
71}
static Domain GenerateDomain()
Definition: ResourceKey.cpp:27
int32_t fBottom
larger y-axis bounds
Definition: SkRect.h:36
int32_t fTop
smaller y-axis bounds
Definition: SkRect.h:34
bool isEmpty() const
Definition: SkRect.h:202
int32_t fLeft
smaller x-axis bounds
Definition: SkRect.h:33
int32_t fRight
larger x-axis bounds
Definition: SkRect.h:35

◆ GrMakeUncachedBitmapProxyView()

std::tuple< GrSurfaceProxyView, GrColorType > GrMakeUncachedBitmapProxyView ( GrRecordingContext rContext,
const SkBitmap bitmap,
skgpu::Mipmapped  mipmapped = skgpu::Mipmapped::kNo,
SkBackingFit  fit = SkBackingFit::kExact,
skgpu::Budgeted  budgeted = skgpu::Budgeted::kYes 
)

Like above but always uploads the bitmap and never inserts into the cache. Unlike above, the texture may be approx or scratch and budgeted or not.

Definition at line 253 of file SkGr.cpp.

258 {
259 GrProxyProvider* proxyProvider = rContext->priv().proxyProvider();
260 const GrCaps* caps = rContext->priv().caps();
261
262 mipmapped = adjust_mipmapped(mipmapped, bitmap, caps);
264
265 if (auto proxy = make_bmp_proxy(proxyProvider, bitmap, ct, mipmapped, fit, budgeted)) {
266 skgpu::Swizzle swizzle = caps->getReadSwizzle(proxy->backendFormat(), ct);
267 SkASSERT(mipmapped == skgpu::Mipmapped::kNo ||
268 proxy->mipmapped() == skgpu::Mipmapped::kYes);
269 return {{std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle}, ct};
270 }
271 return {};
272}

◆ GrMakeUniqueKeyInvalidationListener()

sk_sp< SkIDChangeListener > GrMakeUniqueKeyInvalidationListener ( skgpu::UniqueKey key,
uint32_t  contextID 
)

Makes a SkIDChangeListener from a skgpu::UniqueKey. The key will be invalidated in the resource cache if the ID becomes invalid. This also modifies the key so that it will cause the listener to be deregistered if the key is destroyed (to prevent unbounded listener growth when resources are purged before listeners trigger).

Definition at line 75 of file SkGr.cpp.

76 {
77 class Listener : public SkIDChangeListener {
78 public:
79 Listener(const skgpu::UniqueKey& key, uint32_t contextUniqueID)
80 : fMsg(key, contextUniqueID) {}
81
82 void changed() override {
84 }
85
86 private:
88 };
89
90 auto listener = sk_make_sp<Listener>(*key, contextID);
91
92 // We stick a SkData on the key that calls invalidateListener in its destructor.
93 auto invalidateListener = [](const void* ptr, void* /*context*/) {
94 auto listener = reinterpret_cast<const sk_sp<Listener>*>(ptr);
95 (*listener)->markShouldDeregister();
96 delete listener;
97 };
98 auto data = SkData::MakeWithProc(new sk_sp<Listener>(listener),
99 sizeof(sk_sp<Listener>),
100 invalidateListener,
101 nullptr);
102 SkASSERT(!key->getCustomData());
103 key->setCustomData(std::move(data));
104 return listener;
105}
static sk_sp< SkData > MakeWithProc(const void *ptr, size_t length, ReleaseProc proc, void *ctx)
Definition: SkData.cpp:128
virtual void changed()=0
static void Post(Message m)
Definition: SkMessageBus.h:130
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63

◆ make_bmp_proxy()

static sk_sp< GrTextureProxy > make_bmp_proxy ( GrProxyProvider proxyProvider,
const SkBitmap bitmap,
GrColorType  ct,
skgpu::Mipmapped  mipmapped,
SkBackingFit  fit,
skgpu::Budgeted  budgeted 
)
static

Definition at line 165 of file SkGr.cpp.

170 {
171 SkBitmap bmpToUpload;
172 if (ct != SkColorTypeToGrColorType(bitmap.info().colorType())) {
174 if (!bmpToUpload.tryAllocPixels(bitmap.info().makeColorType(skCT)) ||
175 !bitmap.readPixels(bmpToUpload.pixmap())) {
176 return {};
177 }
178 bmpToUpload.setImmutable();
179 } else {
180 bmpToUpload = bitmap;
181 }
182 auto proxy = proxyProvider->createProxyFromBitmap(bmpToUpload, mipmapped, fit, budgeted);
183 SkASSERT(!proxy || mipmapped == skgpu::Mipmapped::kNo ||
184 proxy->mipmapped() == skgpu::Mipmapped::kYes);
185 return proxy;
186}
static constexpr SkColorType GrColorTypeToSkColorType(GrColorType ct)
Definition: GrTypesPriv.h:589
SkColorType
Definition: SkColorType.h:19
sk_sp< GrTextureProxy > createProxyFromBitmap(const SkBitmap &, skgpu::Mipmapped, SkBackingFit, skgpu::Budgeted)
void setImmutable()
Definition: SkBitmap.cpp:400
const SkPixmap & pixmap() const
Definition: SkBitmap.h:133
bool tryAllocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:271

◆ make_dither_effect()

static std::unique_ptr< GrFragmentProcessor > make_dither_effect ( GrRecordingContext rContext,
std::unique_ptr< GrFragmentProcessor inputFP,
float  range,
const GrCaps caps 
)
static

Definition at line 300 of file SkGr.cpp.

304 {
305 if (range == 0 || inputFP == nullptr) {
306 return inputFP;
307 }
308
309 if (caps->avoidDithering()) {
310 return inputFP;
311 }
312
313 // We used to use integer math on sk_FragCoord, when supported, and a fallback using floating
314 // point (on a 4x4 rather than 8x8 grid). Now we precompute a 8x8 table in a texture because
315 // it was shown to be significantly faster on several devices. Test was done with the following
316 // running in viewer with the stats layer enabled and looking at total frame time:
317 // SkRandom r;
318 // for (int i = 0; i < N; ++i) {
319 // SkColor c[2] = {r.nextU(), r.nextU()};
320 // SkPoint pts[2] = {{r.nextRangeScalar(0, 500), r.nextRangeScalar(0, 500)},
321 // {r.nextRangeScalar(0, 500), r.nextRangeScalar(0, 500)}};
322 // SkPaint p;
323 // p.setDither(true);
324 // p.setShader(SkGradientShader::MakeLinear(pts, c, nullptr, 2, SkTileMode::kRepeat));
325 // canvas->drawPaint(p);
326 // }
327 // Device GPU N no dither int math dither table dither
328 // Linux desktop QuadroP1000 5000 304ms 400ms (1.31x) 383ms (1.26x)
329 // TecnoSpark3Pro PowerVRGE8320 200 299ms 820ms (2.74x) 592ms (1.98x)
330 // Pixel 4 Adreno640 500 110ms 221ms (2.01x) 214ms (1.95x)
331 // Galaxy S20 FE Mali-G77 MP11 600 165ms 360ms (2.18x) 260ms (1.58x)
332 static const SkBitmap gLUT = skgpu::MakeDitherLUT();
333 auto [tex, ct] = GrMakeCachedBitmapProxyView(
334 rContext, gLUT, /*label=*/"MakeDitherEffect", skgpu::Mipmapped::kNo);
335 if (!tex) {
336 return inputFP;
337 }
340 auto te = GrTextureEffect::Make(
341 std::move(tex), kPremul_SkAlphaType, SkMatrix::I(), sampler, *caps);
343 "uniform half range;"
344 "uniform shader inputFP;"
345 "uniform shader table;"
346 "half4 main(float2 xy) {"
347 "half4 color = inputFP.eval(xy);"
348 "half value = table.eval(sk_FragCoord.xy).a - 0.5;" // undo the bias in the table
349 // For each color channel, add the random offset to the channel value and then clamp
350 // between 0 and alpha to keep the color premultiplied.
351 "return half4(clamp(color.rgb + value * range, 0.0, color.a), color.a);"
352 "}"
353 );
354 return GrSkSLFP::Make(effect, "Dither", /*inputFP=*/nullptr,
356 "range", range,
357 "inputFP", std::move(inputFP),
358 "table", GrSkSLFP::IgnoreOptFlags(std::move(te)));
359}
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
std::tuple< GrSurfaceProxyView, GrColorType > GrMakeCachedBitmapProxyView(GrRecordingContext *rContext, const SkBitmap &bitmap, std::string_view label, skgpu::Mipmapped mipmapped)
Definition: SkGr.cpp:188
SkRuntimeEffect * SkMakeRuntimeEffect(SkRuntimeEffect::Result(*make)(SkString, const SkRuntimeEffect::Options &), const char *sksl, SkRuntimeEffect::Options options=SkRuntimeEffect::Options{})
bool avoidDithering() const
Definition: GrCaps.h:546
static GrIgnoreOptFlags IgnoreOptFlags(std::unique_ptr< GrFragmentProcessor > child)
Definition: GrSkSLFP.h:97
static std::unique_ptr< GrSkSLFP > Make(const SkRuntimeEffect *effect, const char *name, std::unique_ptr< GrFragmentProcessor > inputFP, OptFlags optFlags, Args &&... args)
Definition: GrSkSLFP.h:159
static std::unique_ptr< GrFragmentProcessor > Make(GrSurfaceProxyView, SkAlphaType, const SkMatrix &=SkMatrix::I(), GrSamplerState::Filter=GrSamplerState::Filter::kNearest, GrSamplerState::MipmapMode mipmapMode=GrSamplerState::MipmapMode::kNone)
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
static Result MakeForShader(SkString sksl, const Options &)
SkBitmap MakeDitherLUT()
Definition: DitherUtils.cpp:74

◆ SkColor4fPrepForDst()

SkColor4f SkColor4fPrepForDst ( SkColor4f  color,
const GrColorInfo colorInfo 
)

Converts an SkColor4f to the destination color space.

Definition at line 283 of file SkGr.cpp.

283 {
284 if (auto* xform = colorInfo.colorSpaceXformFromSRGB()) {
285 color = xform->apply(color);
286 }
287 return color;
288}
GrColorSpaceXform * colorSpaceXformFromSRGB() const
Definition: GrColorInfo.h:40
DlColor color

◆ SkColorToPMColor4f()

SkPMColor4f SkColorToPMColor4f ( SkColor  c,
const GrColorInfo colorInfo 
)

Similar, but using SkPMColor4f.

Definition at line 275 of file SkGr.cpp.

275 {
276 SkColor4f color = SkColor4f::FromColor(c);
277 if (auto* xform = colorInfo.colorSpaceXformFromSRGB()) {
278 color = xform->apply(color);
279 }
280 return color.premul();
281}

◆ skpaint_to_grpaint_impl()

static bool skpaint_to_grpaint_impl ( GrRecordingContext context,
const GrColorInfo dstColorInfo,
const SkPaint skPaint,
const SkMatrix ctm,
std::optional< std::unique_ptr< GrFragmentProcessor > >  shaderFP,
SkBlender primColorBlender,
const SkSurfaceProps surfaceProps,
GrPaint grPaint 
)
inlinestatic

Definition at line 362 of file SkGr.cpp.

370 {
371 // Convert SkPaint color to 4f format in the destination color space
372 SkColor4f origColor = SkColor4fPrepForDst(skPaint.getColor4f(), dstColorInfo);
373
374 GrFPArgs fpArgs(context, &dstColorInfo, surfaceProps, GrFPArgs::Scope::kDefault);
375
376 // Setup the initial color considering the shader, the SkPaint color, and the presence or not
377 // of per-vertex colors.
378 std::unique_ptr<GrFragmentProcessor> paintFP;
379 const bool gpProvidesShader = shaderFP.has_value() && !*shaderFP;
380 if (!primColorBlender || blender_requires_shader(primColorBlender)) {
381 if (shaderFP.has_value()) {
382 paintFP = std::move(*shaderFP);
383 } else {
384 if (const SkShaderBase* shader = as_SB(skPaint.getShader())) {
385 paintFP = GrFragmentProcessors::Make(shader, fpArgs, ctm);
386 if (paintFP == nullptr) {
387 return false;
388 }
389 }
390 }
391 }
392
393 // Set this in below cases if the output of the shader/paint-color/paint-alpha/primXfermode is
394 // a known constant value. In that case we can simply apply a color filter during this
395 // conversion without converting the color filter to a GrFragmentProcessor.
396 bool applyColorFilterToPaintColor = false;
397 if (paintFP) {
398 if (primColorBlender) {
399 // There is a blend between the primitive color and the shader color. The shader sees
400 // the opaque paint color. The shader's output is blended using the provided mode by
401 // the primitive color. The blended color is then modulated by the paint's alpha.
402
403 // The geometry processor will insert the primitive color to start the color chain, so
404 // the GrPaint color will be ignored.
405
406 SkPMColor4f shaderInput = origColor.makeOpaque().premul();
407 paintFP = GrFragmentProcessor::OverrideInput(std::move(paintFP), shaderInput);
408 paintFP = GrFragmentProcessors::Make(as_BB(primColorBlender),
409 /*srcFP=*/std::move(paintFP),
410 /*dstFP=*/nullptr,
411 fpArgs);
412 if (!paintFP) {
413 return false;
414 }
415
416 // We can ignore origColor here - alpha is unchanged by gamma
417 float paintAlpha = skPaint.getColor4f().fA;
418 if (1.0f != paintAlpha) {
419 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
420 // color channels. It's value should be treated as the same in ANY color space.
422 std::move(paintFP), {paintAlpha, paintAlpha, paintAlpha, paintAlpha});
423 }
424 } else {
425 float paintAlpha = skPaint.getColor4f().fA;
426 if (paintAlpha != 1.0f) {
427 // This invokes the shader's FP tree with an opaque version of the paint color,
428 // then multiplies the final result by the incoming (paint) alpha.
429 // We're actually putting the *unpremul* paint color on the GrPaint. This is okay,
430 // because the shader is supposed to see the original (opaque) RGB from the paint.
431 // ApplyPaintAlpha then creates a valid premul color by applying the paint alpha.
432 // Think of this as equivalent to (but faster than) putting origColor.premul() on
433 // the GrPaint, and ApplyPaintAlpha unpremuling it before passing it to the child.
434 paintFP = GrFragmentProcessor::ApplyPaintAlpha(std::move(paintFP));
435 grPaint->setColor4f({origColor.fR, origColor.fG, origColor.fB, origColor.fA});
436 } else {
437 // paintFP will ignore its input color, so we must disable coverage-as-alpha.
438 // TODO(skbug:11942): The alternative would be to always use ApplyPaintAlpha, but
439 // we'd need to measure the cost of that shader math against the CAA benefit.
440 paintFP = GrFragmentProcessor::DisableCoverageAsAlpha(std::move(paintFP));
441 grPaint->setColor4f(origColor.premul());
442 }
443 }
444 } else {
445 if (primColorBlender) {
446 // The primitive itself has color (e.g. interpolated vertex color) and this is what
447 // the GP will output. Thus, we must get the paint color in separately below as a color
448 // FP. This could be made more efficient if the relevant GPs used GrPaint color and
449 // took the SkBlender to apply with primitive color. As it stands changing the SkPaint
450 // color will break batches.
451 grPaint->setColor4f(SK_PMColor4fWHITE); // won't be used.
452 if (blender_requires_shader(primColorBlender)) {
453 paintFP = GrFragmentProcessor::MakeColor(origColor.makeOpaque().premul());
454 paintFP = GrFragmentProcessors::Make(as_BB(primColorBlender),
455 /*srcFP=*/std::move(paintFP),
456 /*dstFP=*/nullptr,
457 fpArgs);
458 if (!paintFP) {
459 return false;
460 }
461 }
462
463 // The paint's *alpha* is applied after the paint/primitive color blend:
464 // We can ignore origColor here - alpha is unchanged by gamma
465 float paintAlpha = skPaint.getColor4f().fA;
466 if (paintAlpha != 1.0f) {
467 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
468 // color channels. It's value should be treated as the same in ANY color space.
470 std::move(paintFP), {paintAlpha, paintAlpha, paintAlpha, paintAlpha});
471 }
472 } else {
473 // No shader, no primitive color.
474 grPaint->setColor4f(origColor.premul());
475 // We can do this if there isn't a GP that is acting as the shader.
476 applyColorFilterToPaintColor = !gpProvidesShader;
477 }
478 }
479
480 SkColorFilter* colorFilter = skPaint.getColorFilter();
481 if (colorFilter) {
482 if (applyColorFilterToPaintColor) {
483 SkColorSpace* dstCS = dstColorInfo.colorSpace();
484 grPaint->setColor4f(colorFilter->filterColor4f(origColor, dstCS, dstCS).premul());
485 } else {
486 auto [success, fp] = GrFragmentProcessors::Make(
487 context, colorFilter, std::move(paintFP), dstColorInfo, surfaceProps);
488 if (!success) {
489 return false;
490 }
491 paintFP = std::move(fp);
492 }
493 }
494
495 if (auto maskFilter = skPaint.getMaskFilter()) {
496 if (auto mfFP = GrFragmentProcessors::Make(maskFilter, fpArgs, ctm)) {
497 grPaint->setCoverageFragmentProcessor(std::move(mfFP));
498 }
499 }
500
501#ifndef SK_IGNORE_GPU_DITHER
503 if (paintFP != nullptr && (
504 surfaceProps.isAlwaysDither() || SkPaintPriv::ShouldDither(skPaint, ct))) {
505 float ditherRange = skgpu::DitherRangeForConfig(ct);
506 paintFP = make_dither_effect(
507 context, std::move(paintFP), ditherRange, context->priv().caps());
508 }
509#endif
510
511 // Note that for the final blend onto the canvas, we should prefer to use the GrXferProcessor
512 // instead of a SkBlendModeBlender to perform the blend. The Xfer processor is able to perform
513 // coefficient-based blends directly, without readback. This will be much more efficient.
514 if (auto bm = skPaint.asBlendMode()) {
515 // When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field
516 // on the GrPaint to also be null (also kSrcOver).
517 SkASSERT(!grPaint->getXPFactory());
518 if (bm.value() != SkBlendMode::kSrcOver) {
519 grPaint->setXPFactory(GrXPFactory::FromBlendMode(bm.value()));
520 }
521 } else {
522 // Apply a custom blend against the surface color, and force the XP to kSrc so that the
523 // computed result is applied directly to the canvas while still honoring the alpha.
524 paintFP = GrFragmentProcessors::Make(as_BB(skPaint.getBlender()),
525 std::move(paintFP),
527 fpArgs);
528 if (!paintFP) {
529 return false;
530 }
532 }
533
534 if (GrColorTypeClampType(dstColorInfo.colorType()) == GrClampType::kManual) {
535 if (paintFP != nullptr) {
536 paintFP = GrFragmentProcessor::ClampOutput(std::move(paintFP));
537 } else {
538 auto color = grPaint->getColor4f();
539 grPaint->setColor4f({SkTPin(color.fR, 0.f, 1.f),
540 SkTPin(color.fG, 0.f, 1.f),
541 SkTPin(color.fB, 0.f, 1.f),
542 SkTPin(color.fA, 0.f, 1.f)});
543 }
544 }
545
546 if (paintFP) {
547 grPaint->setColorFragmentProcessor(std::move(paintFP));
548 }
549
550 return true;
551}
static constexpr GrClampType GrColorTypeClampType(GrColorType colorType)
Definition: GrTypesPriv.h:868
@ kSrcOver
r = s + (1-sa)*d
constexpr SkPMColor4f SK_PMColor4fWHITE
Definition: SkColorData.h:380
static std::unique_ptr< GrFragmentProcessor > make_dither_effect(GrRecordingContext *rContext, std::unique_ptr< GrFragmentProcessor > inputFP, float range, const GrCaps *caps)
Definition: SkGr.cpp:300
SkColor4f SkColor4fPrepForDst(SkColor4f color, const GrColorInfo &colorInfo)
Definition: SkGr.cpp:283
static bool blender_requires_shader(const SkBlender *blender)
Definition: SkGr.cpp:292
SkShaderBase * as_SB(SkShader *shader)
Definition: SkShaderBase.h:412
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition: SkTPin.h:19
SkColorSpace * colorSpace() const
Definition: GrColorInfo.cpp:48
GrColorType colorType() const
Definition: GrColorInfo.h:43
static std::unique_ptr< GrFragmentProcessor > ClampOutput(std::unique_ptr< GrFragmentProcessor >)
static std::unique_ptr< GrFragmentProcessor > MakeColor(SkPMColor4f color)
static std::unique_ptr< GrFragmentProcessor > ModulateRGBA(std::unique_ptr< GrFragmentProcessor > child, const SkPMColor4f &color)
static std::unique_ptr< GrFragmentProcessor > OverrideInput(std::unique_ptr< GrFragmentProcessor >, const SkPMColor4f &)
static std::unique_ptr< GrFragmentProcessor > SurfaceColor()
static std::unique_ptr< GrFragmentProcessor > ApplyPaintAlpha(std::unique_ptr< GrFragmentProcessor > child)
static std::unique_ptr< GrFragmentProcessor > DisableCoverageAsAlpha(std::unique_ptr< GrFragmentProcessor >)
void setXPFactory(const GrXPFactory *xpFactory)
Definition: GrPaint.h:53
const GrXPFactory * getXPFactory() const
Definition: GrPaint.h:89
const SkPMColor4f & getColor4f() const
Definition: GrPaint.h:51
void setColorFragmentProcessor(std::unique_ptr< GrFragmentProcessor > fp)
Definition: GrPaint.h:65
void setColor4f(const SkPMColor4f &color)
Definition: GrPaint.h:50
void setCoverageFragmentProcessor(std::unique_ptr< GrFragmentProcessor > fp)
Definition: GrPaint.h:75
static const GrXPFactory * FromBlendMode(SkBlendMode)
SkColor4f filterColor4f(const SkColor4f &srcColor, SkColorSpace *srcCS, SkColorSpace *dstCS) const
static bool ShouldDither(const SkPaint &, SkColorType)
SkColorFilter * getColorFilter() const
Definition: SkPaint.h:426
SkColor4f getColor4f() const
Definition: SkPaint.h:232
SkMaskFilter * getMaskFilter() const
Definition: SkPaint.h:534
SkBlender * getBlender() const
Definition: SkPaint.h:480
SkShader * getShader() const
Definition: SkPaint.h:397
std::optional< SkBlendMode > asBlendMode() const
Definition: SkPaint.cpp:138
bool isAlwaysDither() const
std::unique_ptr< GrFragmentProcessor > Make(const SkMaskFilter *maskfilter, const GrFPArgs &args, const SkMatrix &ctm)
const uint32_t fp
float DitherRangeForConfig(SkColorType dstColorType)
Definition: DitherUtils.cpp:20

◆ SkPaintToGrPaint()

bool SkPaintToGrPaint ( GrRecordingContext context,
const GrColorInfo dstColorInfo,
const SkPaint skPaint,
const SkMatrix ctm,
const SkSurfaceProps surfaceProps,
GrPaint grPaint 
)

Converts an SkPaint to a GrPaint for a given GrRecordingContext. The matrix is required in order to convert the SkShader (if any) on the SkPaint. The primitive itself has no color.

Definition at line 553 of file SkGr.cpp.

558 {
559 return skpaint_to_grpaint_impl(context,
560 dstColorInfo,
561 skPaint,
562 ctm,
563 /*shaderFP=*/std::nullopt,
564 /*primColorBlender=*/nullptr,
565 surfaceProps,
566 grPaint);
567}
static bool skpaint_to_grpaint_impl(GrRecordingContext *context, const GrColorInfo &dstColorInfo, const SkPaint &skPaint, const SkMatrix &ctm, std::optional< std::unique_ptr< GrFragmentProcessor > > shaderFP, SkBlender *primColorBlender, const SkSurfaceProps &surfaceProps, GrPaint *grPaint)
Definition: SkGr.cpp:362

◆ SkPaintToGrPaintReplaceShader()

bool SkPaintToGrPaintReplaceShader ( GrRecordingContext context,
const GrColorInfo dstColorInfo,
const SkPaint skPaint,
const SkMatrix ctm,
std::unique_ptr< GrFragmentProcessor shaderFP,
const SkSurfaceProps surfaceProps,
GrPaint grPaint 
)

Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor.

Definition at line 570 of file SkGr.cpp.

576 {
577 return skpaint_to_grpaint_impl(context,
578 dstColorInfo,
579 skPaint,
580 ctm,
581 std::move(shaderFP),
582 /*primColorBlender=*/nullptr,
583 surfaceProps,
584 grPaint);
585}

◆ SkPaintToGrPaintWithBlend()

bool SkPaintToGrPaintWithBlend ( GrRecordingContext context,
const GrColorInfo dstColorInfo,
const SkPaint skPaint,
const SkMatrix ctm,
SkBlender primColorBlender,
const SkSurfaceProps surfaceProps,
GrPaint grPaint 
)

Blends the SkPaint's shader (or color if no shader) with a per-primitive color which must be setup as a vertex attribute using the specified SkBlender.

Definition at line 589 of file SkGr.cpp.

595 {
596 return skpaint_to_grpaint_impl(context,
597 dstColorInfo,
598 skPaint,
599 ctm,
600 /*shaderFP=*/std::nullopt,
601 primColorBlender,
602 surfaceProps,
603 grPaint);
604}