1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2006 The Android Open Source Project
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkBlendShader.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlender.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFlattenable.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkRuntimeEffect.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkBlendModePriv.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkBlenderBase.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkEffectPriv.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkKnownRuntimeEffects.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRasterPipeline.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRasterPipelineOpContexts.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRasterPipelineOpList.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkReadBuffer.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkWriteBuffer.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkShaderBase.h"
26*c8dee2aaSAndroid Build Coastguard Worker
27*c8dee2aaSAndroid Build Coastguard Worker #include <optional>
28*c8dee2aaSAndroid Build Coastguard Worker
CreateProc(SkReadBuffer & buffer)29*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkFlattenable> SkBlendShader::CreateProc(SkReadBuffer& buffer) {
30*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> dst(buffer.readShader());
31*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> src(buffer.readShader());
32*c8dee2aaSAndroid Build Coastguard Worker if (!buffer.validate(dst && src)) {
33*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
34*c8dee2aaSAndroid Build Coastguard Worker }
35*c8dee2aaSAndroid Build Coastguard Worker
36*c8dee2aaSAndroid Build Coastguard Worker unsigned mode = buffer.read32();
37*c8dee2aaSAndroid Build Coastguard Worker
38*c8dee2aaSAndroid Build Coastguard Worker if (mode == kCustom_SkBlendMode) {
39*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkBlender> blender = buffer.readBlender();
40*c8dee2aaSAndroid Build Coastguard Worker if (buffer.validate(blender != nullptr)) {
41*c8dee2aaSAndroid Build Coastguard Worker return SkShaders::Blend(std::move(blender), std::move(dst), std::move(src));
42*c8dee2aaSAndroid Build Coastguard Worker }
43*c8dee2aaSAndroid Build Coastguard Worker } else {
44*c8dee2aaSAndroid Build Coastguard Worker if (buffer.validate(mode <= (unsigned)SkBlendMode::kLastMode)) {
45*c8dee2aaSAndroid Build Coastguard Worker return SkShaders::Blend(static_cast<SkBlendMode>(mode), std::move(dst), std::move(src));
46*c8dee2aaSAndroid Build Coastguard Worker }
47*c8dee2aaSAndroid Build Coastguard Worker }
48*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker
flatten(SkWriteBuffer & buffer) const51*c8dee2aaSAndroid Build Coastguard Worker void SkBlendShader::flatten(SkWriteBuffer& buffer) const {
52*c8dee2aaSAndroid Build Coastguard Worker buffer.writeFlattenable(fDst.get());
53*c8dee2aaSAndroid Build Coastguard Worker buffer.writeFlattenable(fSrc.get());
54*c8dee2aaSAndroid Build Coastguard Worker buffer.write32((int)fMode);
55*c8dee2aaSAndroid Build Coastguard Worker }
56*c8dee2aaSAndroid Build Coastguard Worker
57*c8dee2aaSAndroid Build Coastguard Worker // Returns the output of e0, and leaves the output of e1 in r,g,b,a
append_two_shaders(const SkStageRec & rec,const SkShaders::MatrixRec & mRec,SkShader * s0,SkShader * s1)58*c8dee2aaSAndroid Build Coastguard Worker static float* append_two_shaders(const SkStageRec& rec,
59*c8dee2aaSAndroid Build Coastguard Worker const SkShaders::MatrixRec& mRec,
60*c8dee2aaSAndroid Build Coastguard Worker SkShader* s0,
61*c8dee2aaSAndroid Build Coastguard Worker SkShader* s1) {
62*c8dee2aaSAndroid Build Coastguard Worker struct Storage {
63*c8dee2aaSAndroid Build Coastguard Worker float fCoords[2 * SkRasterPipeline_kMaxStride];
64*c8dee2aaSAndroid Build Coastguard Worker float fRes0[4 * SkRasterPipeline_kMaxStride];
65*c8dee2aaSAndroid Build Coastguard Worker };
66*c8dee2aaSAndroid Build Coastguard Worker auto storage = rec.fAlloc->make<Storage>();
67*c8dee2aaSAndroid Build Coastguard Worker
68*c8dee2aaSAndroid Build Coastguard Worker // Note we cannot simply apply mRec here and then unconditionally store the coordinates. When
69*c8dee2aaSAndroid Build Coastguard Worker // building for Android Framework it would interrupt the backwards local matrix concatenation if
70*c8dee2aaSAndroid Build Coastguard Worker // mRec had a pending local matrix and either of the children also had a local matrix.
71*c8dee2aaSAndroid Build Coastguard Worker // b/256873449
72*c8dee2aaSAndroid Build Coastguard Worker if (mRec.rasterPipelineCoordsAreSeeded()) {
73*c8dee2aaSAndroid Build Coastguard Worker rec.fPipeline->append(SkRasterPipelineOp::store_src_rg, storage->fCoords);
74*c8dee2aaSAndroid Build Coastguard Worker }
75*c8dee2aaSAndroid Build Coastguard Worker if (!as_SB(s0)->appendStages(rec, mRec)) {
76*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker rec.fPipeline->append(SkRasterPipelineOp::store_src, storage->fRes0);
79*c8dee2aaSAndroid Build Coastguard Worker
80*c8dee2aaSAndroid Build Coastguard Worker if (mRec.rasterPipelineCoordsAreSeeded()) {
81*c8dee2aaSAndroid Build Coastguard Worker rec.fPipeline->append(SkRasterPipelineOp::load_src_rg, storage->fCoords);
82*c8dee2aaSAndroid Build Coastguard Worker }
83*c8dee2aaSAndroid Build Coastguard Worker if (!as_SB(s1)->appendStages(rec, mRec)) {
84*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
85*c8dee2aaSAndroid Build Coastguard Worker }
86*c8dee2aaSAndroid Build Coastguard Worker return storage->fRes0;
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker
appendStages(const SkStageRec & rec,const SkShaders::MatrixRec & mRec) const89*c8dee2aaSAndroid Build Coastguard Worker bool SkBlendShader::appendStages(const SkStageRec& rec, const SkShaders::MatrixRec& mRec) const {
90*c8dee2aaSAndroid Build Coastguard Worker float* res0 = append_two_shaders(rec, mRec, fDst.get(), fSrc.get());
91*c8dee2aaSAndroid Build Coastguard Worker if (!res0) {
92*c8dee2aaSAndroid Build Coastguard Worker return false;
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker
95*c8dee2aaSAndroid Build Coastguard Worker rec.fPipeline->append(SkRasterPipelineOp::load_dst, res0);
96*c8dee2aaSAndroid Build Coastguard Worker SkBlendMode_AppendStages(fMode, rec.fPipeline);
97*c8dee2aaSAndroid Build Coastguard Worker return true;
98*c8dee2aaSAndroid Build Coastguard Worker }
99*c8dee2aaSAndroid Build Coastguard Worker
Blend(SkBlendMode mode,sk_sp<SkShader> dst,sk_sp<SkShader> src)100*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> SkShaders::Blend(SkBlendMode mode, sk_sp<SkShader> dst, sk_sp<SkShader> src) {
101*c8dee2aaSAndroid Build Coastguard Worker if (!src || !dst) {
102*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
103*c8dee2aaSAndroid Build Coastguard Worker }
104*c8dee2aaSAndroid Build Coastguard Worker switch (mode) {
105*c8dee2aaSAndroid Build Coastguard Worker case SkBlendMode::kClear:
106*c8dee2aaSAndroid Build Coastguard Worker return Color(0);
107*c8dee2aaSAndroid Build Coastguard Worker case SkBlendMode::kDst:
108*c8dee2aaSAndroid Build Coastguard Worker return dst;
109*c8dee2aaSAndroid Build Coastguard Worker case SkBlendMode::kSrc:
110*c8dee2aaSAndroid Build Coastguard Worker return src;
111*c8dee2aaSAndroid Build Coastguard Worker default:
112*c8dee2aaSAndroid Build Coastguard Worker break;
113*c8dee2aaSAndroid Build Coastguard Worker }
114*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<SkShader>(new SkBlendShader(mode, std::move(dst), std::move(src)));
115*c8dee2aaSAndroid Build Coastguard Worker }
116*c8dee2aaSAndroid Build Coastguard Worker
Blend(sk_sp<SkBlender> blender,sk_sp<SkShader> dst,sk_sp<SkShader> src)117*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> SkShaders::Blend(sk_sp<SkBlender> blender,
118*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> dst,
119*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> src) {
120*c8dee2aaSAndroid Build Coastguard Worker using namespace SkKnownRuntimeEffects;
121*c8dee2aaSAndroid Build Coastguard Worker
122*c8dee2aaSAndroid Build Coastguard Worker if (!src || !dst) {
123*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
124*c8dee2aaSAndroid Build Coastguard Worker }
125*c8dee2aaSAndroid Build Coastguard Worker if (!blender) {
126*c8dee2aaSAndroid Build Coastguard Worker return SkShaders::Blend(SkBlendMode::kSrcOver, std::move(dst), std::move(src));
127*c8dee2aaSAndroid Build Coastguard Worker }
128*c8dee2aaSAndroid Build Coastguard Worker if (std::optional<SkBlendMode> mode = as_BB(blender)->asBlendMode()) {
129*c8dee2aaSAndroid Build Coastguard Worker return sk_make_sp<SkBlendShader>(mode.value(), std::move(dst), std::move(src));
130*c8dee2aaSAndroid Build Coastguard Worker }
131*c8dee2aaSAndroid Build Coastguard Worker
132*c8dee2aaSAndroid Build Coastguard Worker // This isn't a built-in blend mode; we might as well use a runtime effect to evaluate it.
133*c8dee2aaSAndroid Build Coastguard Worker const SkRuntimeEffect* blendEffect = GetKnownRuntimeEffect(StableKey::kBlend);
134*c8dee2aaSAndroid Build Coastguard Worker
135*c8dee2aaSAndroid Build Coastguard Worker SkRuntimeEffect::ChildPtr children[] = {std::move(src), std::move(dst), std::move(blender)};
136*c8dee2aaSAndroid Build Coastguard Worker return blendEffect->makeShader(/*uniforms=*/{}, children);
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker
SkRegisterBlendShaderFlattenable()139*c8dee2aaSAndroid Build Coastguard Worker void SkRegisterBlendShaderFlattenable() {
140*c8dee2aaSAndroid Build Coastguard Worker SK_REGISTER_FLATTENABLE(SkBlendShader);
141*c8dee2aaSAndroid Build Coastguard Worker // Previous name
142*c8dee2aaSAndroid Build Coastguard Worker SkFlattenable::Register("SkShader_Blend", SkBlendShader::CreateProc);
143*c8dee2aaSAndroid Build Coastguard Worker }
144