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
8 #include "src/effects/colorfilters/SkRuntimeColorFilter.h"
9
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkCapabilities.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkColorFilter.h"
14 #include "include/core/SkData.h"
15 #include "include/core/SkMatrix.h"
16 #include "include/core/SkString.h"
17 #include "include/effects/SkLumaColorFilter.h"
18 #include "include/effects/SkOverdrawColorFilter.h"
19 #include "include/effects/SkRuntimeEffect.h"
20 #include "include/private/SkColorData.h"
21 #include "include/private/SkSLSampleUsage.h"
22 #include "include/private/base/SkDebug.h"
23 #include "include/private/base/SkFloatingPoint.h"
24 #include "include/private/base/SkTArray.h"
25 #include "src/core/SkEffectPriv.h"
26 #include "src/core/SkKnownRuntimeEffects.h"
27 #include "src/core/SkReadBuffer.h"
28 #include "src/core/SkRuntimeEffectPriv.h"
29 #include "src/core/SkWriteBuffer.h"
30 #include "src/shaders/SkShaderBase.h"
31 #include "src/sksl/codegen/SkSLRasterPipelineBuilder.h"
32
33 #include <string>
34 #include <utility>
35
36 #if defined(SK_BUILD_FOR_DEBUGGER)
37 constexpr bool kLenientSkSLDeserialization = true;
38 #else
39 constexpr bool kLenientSkSLDeserialization = false;
40 #endif
41
SkRuntimeColorFilter(sk_sp<SkRuntimeEffect> effect,sk_sp<const SkData> uniforms,SkSpan<const SkRuntimeEffect::ChildPtr> children)42 SkRuntimeColorFilter::SkRuntimeColorFilter(sk_sp<SkRuntimeEffect> effect,
43 sk_sp<const SkData> uniforms,
44 SkSpan<const SkRuntimeEffect::ChildPtr> children)
45 : fEffect(std::move(effect))
46 , fUniforms(std::move(uniforms))
47 , fChildren(children.begin(), children.end()) {}
48
appendStages(const SkStageRec & rec,bool) const49 bool SkRuntimeColorFilter::appendStages(const SkStageRec& rec, bool) const {
50 if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(), fEffect.get())) {
51 // SkRP has support for many parts of #version 300 already, but for now, we restrict its
52 // usage in runtime effects to just #version 100.
53 return false;
54 }
55 if (const SkSL::RP::Program* program = fEffect->getRPProgram(/*debugTrace=*/nullptr)) {
56 SkSpan<const float> uniforms =
57 SkRuntimeEffectPriv::UniformsAsSpan(fEffect->uniforms(),
58 fUniforms,
59 /*alwaysCopyIntoAlloc=*/false,
60 rec.fDstCS,
61 rec.fAlloc);
62 SkShaders::MatrixRec matrix(SkMatrix::I());
63 matrix.markCTMApplied();
64 RuntimeEffectRPCallbacks callbacks(rec, matrix, fChildren, fEffect->fSampleUsages);
65 bool success = program->appendStages(rec.fPipeline, rec.fAlloc, &callbacks, uniforms);
66 return success;
67 }
68 return false;
69 }
70
onIsAlphaUnchanged() const71 bool SkRuntimeColorFilter::onIsAlphaUnchanged() const {
72 return fEffect->isAlphaUnchanged();
73 }
74
flatten(SkWriteBuffer & buffer) const75 void SkRuntimeColorFilter::flatten(SkWriteBuffer& buffer) const {
76 buffer.writeString(fEffect->source().c_str());
77 buffer.writeDataAsByteArray(fUniforms.get());
78 SkRuntimeEffectPriv::WriteChildEffects(buffer, fChildren);
79 }
80
asRuntimeEffect() const81 SkRuntimeEffect* SkRuntimeColorFilter::asRuntimeEffect() const { return fEffect.get(); }
82
CreateProc(SkReadBuffer & buffer)83 sk_sp<SkFlattenable> SkRuntimeColorFilter::CreateProc(SkReadBuffer& buffer) {
84 if (!buffer.validate(buffer.allowSkSL())) {
85 return nullptr;
86 }
87
88 SkString sksl;
89 buffer.readString(&sksl);
90 sk_sp<SkData> uniforms = buffer.readByteArrayAsData();
91
92 auto effect = SkMakeCachedRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, std::move(sksl));
93 if constexpr (!kLenientSkSLDeserialization) {
94 if (!buffer.validate(effect != nullptr)) {
95 return nullptr;
96 }
97 }
98
99 skia_private::STArray<4, SkRuntimeEffect::ChildPtr> children;
100 if (!SkRuntimeEffectPriv::ReadChildEffects(buffer, effect.get(), &children)) {
101 return nullptr;
102 }
103
104 if constexpr (kLenientSkSLDeserialization) {
105 if (!effect) {
106 SkDebugf("Serialized SkSL failed to compile. Ignoring/dropping SkSL color filter.\n");
107 return nullptr;
108 }
109 }
110
111 return effect->makeColorFilter(std::move(uniforms), SkSpan(children));
112 }
113
114 /////////////////////////////////////////////////////////////////////////////////////////////////
115
Lerp(float weight,sk_sp<SkColorFilter> cf0,sk_sp<SkColorFilter> cf1)116 sk_sp<SkColorFilter> SkColorFilters::Lerp(float weight, sk_sp<SkColorFilter> cf0,
117 sk_sp<SkColorFilter> cf1) {
118 using namespace SkKnownRuntimeEffects;
119
120 if (!cf0 && !cf1) {
121 return nullptr;
122 }
123 if (SkIsNaN(weight)) {
124 return nullptr;
125 }
126
127 if (cf0 == cf1) {
128 return cf0; // or cf1
129 }
130
131 if (weight <= 0) {
132 return cf0;
133 }
134 if (weight >= 1) {
135 return cf1;
136 }
137
138 const SkRuntimeEffect* lerpEffect = GetKnownRuntimeEffect(StableKey::kLerp);
139
140 sk_sp<SkColorFilter> inputs[] = {cf0,cf1};
141 return lerpEffect->makeColorFilter(SkData::MakeWithCopy(&weight, sizeof(weight)),
142 inputs, std::size(inputs));
143 }
144
Make()145 sk_sp<SkColorFilter> SkLumaColorFilter::Make() {
146 using namespace SkKnownRuntimeEffects;
147
148 const SkRuntimeEffect* lumaEffect = GetKnownRuntimeEffect(StableKey::kLuma);
149
150 return lumaEffect->makeColorFilter(SkData::MakeEmpty());
151 }
152
MakeWithSkColors(const SkColor colors[kNumColors])153 sk_sp<SkColorFilter> SkOverdrawColorFilter::MakeWithSkColors(const SkColor colors[kNumColors]) {
154 using namespace SkKnownRuntimeEffects;
155
156 const SkRuntimeEffect* overdrawEffect = GetKnownRuntimeEffect(StableKey::kOverdraw);
157
158 auto data = SkData::MakeUninitialized(kNumColors * sizeof(SkPMColor4f));
159 SkPMColor4f* premul = (SkPMColor4f*)data->writable_data();
160 for (int i = 0; i < kNumColors; ++i) {
161 premul[i] = SkColor4f::FromColor(colors[i]).premul();
162 }
163 return overdrawEffect->makeColorFilter(std::move(data));
164 }
165