Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
PaintParams.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2022 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 "src/gpu/Blend.h"
17#include "src/gpu/DitherUtils.h"
26
27namespace skgpu::graphite {
28
29namespace {
30
31// This should be kept in sync w/ SkPaintPriv::ShouldDither and PaintOption::shouldDither
32bool should_dither(const PaintParams& p, SkColorType dstCT) {
33 // The paint dither flag can veto.
34 if (!p.dither()) {
35 return false;
36 }
37
38 if (dstCT == kUnknown_SkColorType) {
39 return false;
40 }
41
42 // We always dither 565 or 4444 when requested.
43 if (dstCT == kRGB_565_SkColorType || dstCT == kARGB_4444_SkColorType) {
44 return true;
45 }
46
47 // Otherwise, dither is only needed for non-const paints.
48 return p.shader() && !as_SB(p.shader())->isConstant();
49}
50
51} // anonymous namespace
52
54 sk_sp<SkBlender> primitiveBlender,
55 sk_sp<SkShader> clipShader,
56 DstReadRequirement dstReadReq,
57 bool skipColorXform)
58 : fColor(paint.getColor4f())
59 , fFinalBlender(paint.refBlender())
60 , fShader(paint.refShader())
61 , fColorFilter(paint.refColorFilter())
62 , fPrimitiveBlender(std::move(primitiveBlender))
63 , fClipShader(std::move(clipShader))
64 , fDstReadReq(dstReadReq)
65 , fSkipColorXform(skipColorXform)
66 , fDither(paint.isDither()) {}
67
68PaintParams::PaintParams(const PaintParams& other) = default;
70PaintParams& PaintParams::operator=(const PaintParams& other) = default;
71
72std::optional<SkBlendMode> PaintParams::asFinalBlendMode() const {
73 return fFinalBlender ? as_BB(fFinalBlender)->asBlendMode()
75}
76
77sk_sp<SkBlender> PaintParams::refFinalBlender() const { return fFinalBlender; }
78
79sk_sp<SkShader> PaintParams::refShader() const { return fShader; }
80
81sk_sp<SkColorFilter> PaintParams::refColorFilter() const { return fColorFilter; }
82
83sk_sp<SkBlender> PaintParams::refPrimitiveBlender() const { return fPrimitiveBlender; }
84
86 // xform from sRGB to the destination colorspace
88 dstColorInfo.colorSpace(), kUnpremul_SkAlphaType);
89
90 SkColor4f result = srcColor;
91 steps.apply(result.vec());
92 return result;
93}
94
95void Blend(const KeyContext& keyContext,
96 PaintParamsKeyBuilder* keyBuilder,
97 PipelineDataGatherer* gatherer,
98 AddToKeyFn addBlendToKey,
99 AddToKeyFn addSrcToKey,
100 AddToKeyFn addDstToKey) {
101 BlendShaderBlock::BeginBlock(keyContext, keyBuilder, gatherer);
102
103 addSrcToKey();
104
105 addDstToKey();
106
107 addBlendToKey();
108
109 keyBuilder->endBlock(); // BlendShaderBlock
110}
111
112void Compose(const KeyContext& keyContext,
113 PaintParamsKeyBuilder* keyBuilder,
114 PipelineDataGatherer* gatherer,
115 AddToKeyFn addInnerToKey,
116 AddToKeyFn addOuterToKey) {
117 ComposeBlock::BeginBlock(keyContext, keyBuilder, gatherer);
118
119 addInnerToKey();
120
121 addOuterToKey();
122
123 keyBuilder->endBlock(); // ComposeBlock
124}
125
126void AddKnownModeBlend(const KeyContext& keyContext,
127 PaintParamsKeyBuilder* builder,
128 PipelineDataGatherer* gatherer,
129 SkBlendMode bm) {
132 static_cast<int>(bm));
133 builder->addBlock(id);
134}
135
136void AddModeBlend(const KeyContext& keyContext,
137 PaintParamsKeyBuilder* builder,
138 PipelineDataGatherer* gatherer,
139 SkBlendMode bm) {
141 if (!coeffs.empty()) {
142 CoeffBlenderBlock::AddBlock(keyContext, builder, gatherer, coeffs);
143 } else {
144 BlendModeBlenderBlock::AddBlock(keyContext, builder, gatherer, bm);
145 }
146}
147
148void AddDstReadBlock(const KeyContext& keyContext,
149 PaintParamsKeyBuilder* builder,
150 PipelineDataGatherer* gatherer,
151 DstReadRequirement dstReadReq) {
152 switch(dstReadReq) {
154 SkASSERT(false); // This should never be reached
155 return;
157 [[fallthrough]];
159 DstReadSampleBlock::AddBlock(keyContext, builder, gatherer, keyContext.dstTexture(),
160 keyContext.dstOffset());
161 break;
163 builder->addBlock(BuiltInCodeSnippetID::kDstReadFetch);
164 break;
165 }
166}
167
168void AddDitherBlock(const KeyContext& keyContext,
169 PaintParamsKeyBuilder* builder,
170 PipelineDataGatherer* gatherer,
171 SkColorType ct) {
172 static const SkBitmap gLUT = skgpu::MakeDitherLUT();
173
175 if (keyContext.recorder() && !proxy) {
176 SKGPU_LOG_W("Couldn't create dither shader's LUT");
177 builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
178 return;
179 }
180
182
183 DitherShaderBlock::AddBlock(keyContext, builder, gatherer, data);
184}
185
186void PaintParams::addPaintColorToKey(const KeyContext& keyContext,
187 PaintParamsKeyBuilder* keyBuilder,
188 PipelineDataGatherer* gatherer) const {
189 if (fShader) {
190 AddToKey(keyContext, keyBuilder, gatherer, fShader.get());
191 } else {
192 RGBPaintColorBlock::AddBlock(keyContext, keyBuilder, gatherer);
193 }
194}
195
196/**
197 * Primitive blend blocks are used to blend either the paint color or the output of another shader
198 * with a primitive color emitted by certain draw geometry calls (drawVertices, drawAtlas, etc.).
199 * Dst: primitiveColor Src: Paint color/shader output
200 */
201void PaintParams::handlePrimitiveColor(const KeyContext& keyContext,
202 PaintParamsKeyBuilder* keyBuilder,
203 PipelineDataGatherer* gatherer) const {
204 if (fPrimitiveBlender) {
205 Blend(keyContext, keyBuilder, gatherer,
206 /* addBlendToKey= */ [&] () -> void {
207 AddToKey(keyContext, keyBuilder, gatherer, fPrimitiveBlender.get());
208 },
209 /* addSrcToKey= */ [&]() -> void {
210 this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
211 },
212 /* addDstToKey= */ [&]() -> void {
213 keyBuilder->addBlock(BuiltInCodeSnippetID::kPrimitiveColor);
214 });
215 } else {
216 this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
217 }
218}
219
220// Apply the paint's alpha value.
221void PaintParams::handlePaintAlpha(const KeyContext& keyContext,
222 PaintParamsKeyBuilder* keyBuilder,
223 PipelineDataGatherer* gatherer) const {
224
225 if (!fShader && !fPrimitiveBlender) {
226 // If there is no shader and no primitive blending the input to the colorFilter stage
227 // is just the premultiplied paint color.
229 keyContext.dstColorInfo()).premul();
230 SolidColorShaderBlock::AddBlock(keyContext, keyBuilder, gatherer, paintColor);
231 return;
232 }
233
234 if (fColor.fA != 1.0f) {
235 Blend(keyContext, keyBuilder, gatherer,
236 /* addBlendToKey= */ [&] () -> void {
237 AddKnownModeBlend(keyContext, keyBuilder, gatherer, SkBlendMode::kSrcIn);
238 },
239 /* addSrcToKey= */ [&]() -> void {
240 this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
241 },
242 /* addDstToKey= */ [&]() -> void {
243 AlphaOnlyPaintColorBlock::AddBlock(keyContext, keyBuilder, gatherer);
244 });
245 } else {
246 this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
247 }
248}
249
250void PaintParams::handleColorFilter(const KeyContext& keyContext,
251 PaintParamsKeyBuilder* builder,
252 PipelineDataGatherer* gatherer) const {
253 if (fColorFilter) {
254 Compose(keyContext, builder, gatherer,
255 /* addInnerToKey= */ [&]() -> void {
256 this->handlePaintAlpha(keyContext, builder, gatherer);
257 },
258 /* addOuterToKey= */ [&]() -> void {
259 AddToKey(keyContext, builder, gatherer, fColorFilter.get());
260 });
261 } else {
262 this->handlePaintAlpha(keyContext, builder, gatherer);
263 }
264}
265
266void PaintParams::handleDithering(const KeyContext& keyContext,
267 PaintParamsKeyBuilder* builder,
268 PipelineDataGatherer* gatherer) const {
269
270#ifndef SK_IGNORE_GPU_DITHER
271 SkColorType ct = keyContext.dstColorInfo().colorType();
272 if (should_dither(*this, ct)) {
273 Compose(keyContext, builder, gatherer,
274 /* addInnerToKey= */ [&]() -> void {
275 this->handleColorFilter(keyContext, builder, gatherer);
276 },
277 /* addOuterToKey= */ [&]() -> void {
278 AddDitherBlock(keyContext, builder, gatherer, ct);
279 });
280 } else
281#endif
282 {
283 this->handleColorFilter(keyContext, builder, gatherer);
284 }
285}
286
287void PaintParams::handleDstRead(const KeyContext& keyContext,
288 PaintParamsKeyBuilder* builder,
289 PipelineDataGatherer* gatherer) const {
290 if (fDstReadReq != DstReadRequirement::kNone) {
291 Blend(keyContext, builder, gatherer,
292 /* addBlendToKey= */ [&] () -> void {
293 if (fFinalBlender) {
294 AddToKey(keyContext, builder, gatherer, fFinalBlender.get());
295 } else {
296 AddKnownModeBlend(keyContext, builder, gatherer, SkBlendMode::kSrcOver);
297 }
298 },
299 /* addSrcToKey= */ [&]() -> void {
300 this->handleDithering(keyContext, builder, gatherer);
301 },
302 /* addDstToKey= */ [&]() -> void {
303 AddDstReadBlock(keyContext, builder, gatherer, fDstReadReq);
304 });
305 } else {
306 this->handleDithering(keyContext, builder, gatherer);
307 }
308}
309
310void PaintParams::toKey(const KeyContext& keyContext,
311 PaintParamsKeyBuilder* builder,
312 PipelineDataGatherer* gatherer) const {
313 this->handleDstRead(keyContext, builder, gatherer);
314
315 std::optional<SkBlendMode> finalBlendMode = this->asFinalBlendMode();
316 if (fDstReadReq != DstReadRequirement::kNone) {
317 // In this case the blend will have been handled by shader-based blending with the dstRead.
318 finalBlendMode = SkBlendMode::kSrc;
319 }
320
321 if (fClipShader) {
322 ClipShaderBlock::BeginBlock(keyContext, builder, gatherer);
323
324 AddToKey(keyContext, builder, gatherer, fClipShader.get());
325
326 builder->endBlock();
327 }
328
329 // Set the hardware blend mode.
330 SkASSERT(finalBlendMode);
331 BuiltInCodeSnippetID fixedFuncBlendModeID = static_cast<BuiltInCodeSnippetID>(
332 kFixedFunctionBlendModeIDOffset + static_cast<int>(*finalBlendMode));
333
334 builder->addBlock(fixedFuncBlendModeID);
335}
336
337// TODO(b/330864257): Can be deleted once keys are determined by the Device draw.
339 DrawContext* drawContext) const {
340 if (fShader) {
341 NotifyImagesInUse(recorder, drawContext, fShader.get());
342 }
343 if (fPrimitiveBlender) {
344 NotifyImagesInUse(recorder, drawContext, fPrimitiveBlender.get());
345 }
346 if (fColorFilter) {
347 NotifyImagesInUse(recorder, drawContext, fColorFilter.get());
348 }
349 if (fFinalBlender) {
350 NotifyImagesInUse(recorder, drawContext, fFinalBlender.get());
351 }
352 if (fClipShader) {
353 NotifyImagesInUse(recorder, drawContext, fClipShader.get());
354 }
355}
356
357} // namespace skgpu::graphite
#define SKGPU_LOG_W(fmt,...)
Definition Log.h:40
kUnpremul_SkAlphaType
#define SkASSERT(cond)
Definition SkAssert.h:116
SkBlendMode
Definition SkBlendMode.h:38
@ kLastCoeffMode
last porter duff blend mode
@ kSrcOver
r = s + (1-sa)*d
@ kSrcIn
r = s * da
SkBlenderBase * as_BB(SkBlender *blend)
SkColorSpace * sk_srgb_singleton()
SkColorType
Definition SkColorType.h:19
@ kARGB_4444_SkColorType
pixel with 4 bits for alpha, red, green, blue; in 16-bit word
Definition SkColorType.h:23
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition SkColorType.h:22
@ kUnknown_SkColorType
uninitialized
Definition SkColorType.h:20
SkShaderBase * as_SB(SkShader *shader)
virtual std::optional< SkBlendMode > asBlendMode() const
SkColorSpace * colorSpace() const
virtual bool isConstant() const
T * get() const
Definition SkRefCnt.h:303
SkIPoint dstOffset() const
Definition KeyContext.h:70
Recorder * recorder() const
Definition KeyContext.h:55
sk_sp< TextureProxy > dstTexture() const
Definition KeyContext.h:68
PaintParams & operator=(const PaintParams &)
sk_sp< SkBlender > refFinalBlender() const
sk_sp< SkBlender > refPrimitiveBlender() const
void toKey(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *) const
PaintParams(const SkPaint &, sk_sp< SkBlender > primitiveBlender, sk_sp< SkShader > clipShader, DstReadRequirement dstReadReq, bool skipColorXform)
std::optional< SkBlendMode > asFinalBlendMode() const
static SkColor4f Color4fPrepForDst(SkColor4f srgb, const SkColorInfo &dstColorInfo)
sk_sp< SkColorFilter > refColorFilter() const
void notifyImagesInUse(Recorder *, DrawContext *) const
sk_sp< SkShader > refShader() const
static sk_sp< TextureProxy > CreateCachedProxy(Recorder *, const SkBitmap &, Mipmapped=skgpu::Mipmapped::kNo)
Definition Recorder.cpp:536
const Paint & paint
GAsyncResult * result
static constexpr int kFixedFunctionBlendModeIDOffset
void AddToKey(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, const SkBlender *blender)
std::function< void()> AddToKeyFn
Definition PaintParams.h:97
void AddKnownModeBlend(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkBlendMode bm)
void Compose(const KeyContext &keyContext, PaintParamsKeyBuilder *keyBuilder, PipelineDataGatherer *gatherer, AddToKeyFn addInnerToKey, AddToKeyFn addOuterToKey)
void AddDitherBlock(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkColorType ct)
void AddDstReadBlock(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, DstReadRequirement dstReadReq)
void Blend(const KeyContext &keyContext, PaintParamsKeyBuilder *keyBuilder, PipelineDataGatherer *gatherer, AddToKeyFn addBlendToKey, AddToKeyFn addSrcToKey, AddToKeyFn addDstToKey)
void AddModeBlend(const KeyContext &keyContext, PaintParamsKeyBuilder *builder, PipelineDataGatherer *gatherer, SkBlendMode bm)
void NotifyImagesInUse(Recorder *recorder, DrawContext *drawContext, const SkBlender *blender)
float DitherRangeForConfig(SkColorType dstColorType)
SkBitmap MakeDitherLUT()
SkSpan< const float > GetPorterDuffBlendConstants(SkBlendMode mode)
Definition Blend.cpp:53
Definition ref_ptr.h:256
void apply(float rgba[4]) const
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, SkBlendMode)
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, SkSpan< const float > coeffs)
static void BeginBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const DitherData &)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, sk_sp< TextureProxy > dst, SkIPoint dstOffset)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *)
static void AddBlock(const KeyContext &, PaintParamsKeyBuilder *, PipelineDataGatherer *, const SkPMColor4f &)