1 /*
2  * Copyright 2019 Google Inc.
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 "include/core/SkData.h"
9 #include "src/core/SkArenaAlloc.h"
10 #include "src/core/SkRasterPipeline.h"
11 #include "src/core/SkReadBuffer.h"
12 #include "src/core/SkWriteBuffer.h"
13 #include "src/shaders/SkRTShader.h"
14 
15 #include "src/sksl/SkSLByteCode.h"
16 #include "src/sksl/SkSLCompiler.h"
17 
18 #if SK_SUPPORT_GPU
19 #include "include/private/GrRecordingContext.h"
20 #include "src/gpu/GrCaps.h"
21 #include "src/gpu/GrColorInfo.h"
22 #include "src/gpu/GrRecordingContextPriv.h"
23 #include "src/gpu/SkGr.h"
24 
25 #include "src/gpu/GrFragmentProcessor.h"
26 #include "src/gpu/effects/GrSkSLFP.h"
27 #include "src/gpu/effects/generated/GrMixerEffect.h"
28 
new_sksl_unique_id()29 static inline uint32_t new_sksl_unique_id() {
30     return GrSkSLFP::NewIndex();
31 }
32 #else
new_sksl_unique_id()33 static inline uint32_t new_sksl_unique_id() {
34     return 0;   // not used w/o GPU
35 }
36 #endif
37 
SkRTShader(int index,SkString sksl,sk_sp<SkData> inputs,const SkMatrix * localMatrix,bool isOpaque)38 SkRTShader::SkRTShader(int index, SkString sksl, sk_sp<SkData> inputs, const SkMatrix* localMatrix,
39                        bool isOpaque)
40     : SkShaderBase(localMatrix)
41     , fSkSL(std::move(sksl))
42     , fInputs(std::move(inputs))
43     , fUniqueID(index)
44     , fIsOpaque(isOpaque)
45 {}
46 
onAppendStages(const SkStageRec & rec) const47 bool SkRTShader::onAppendStages(const SkStageRec& rec) const {
48     SkMatrix inverse;
49     if (!this->computeTotalInverse(rec.fCTM, rec.fLocalM, &inverse)) {
50         return false;
51     }
52 
53     auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
54     ctx->paintColor = rec.fPaint.getColor4f();
55     ctx->inputs = fInputs->data();
56     ctx->ninputs = fInputs->size() / 4;
57     ctx->shaderConvention = true;
58 
59     SkAutoMutexExclusive ama(fByteCodeMutex);
60     if (!fByteCode) {
61         SkSL::Compiler c;
62         auto prog = c.convertProgram(SkSL::Program::kPipelineStage_Kind,
63                                      SkSL::String(fSkSL.c_str()),
64                                      SkSL::Program::Settings());
65         if (c.errorCount()) {
66             SkDebugf("%s\n", c.errorText().c_str());
67             return false;
68         }
69         fByteCode = c.toByteCode(*prog);
70         if (c.errorCount()) {
71             SkDebugf("%s\n", c.errorText().c_str());
72             return false;
73         }
74         SkASSERT(fByteCode);
75         if (!fByteCode->getFunction("main")) {
76             return false;
77         }
78     }
79     ctx->byteCode = fByteCode.get();
80     ctx->fn = ctx->byteCode->getFunction("main");
81 
82     rec.fPipeline->append(SkRasterPipeline::seed_shader);
83     rec.fPipeline->append_matrix(rec.fAlloc, inverse);
84     rec.fPipeline->append(SkRasterPipeline::interpreter, ctx);
85     return true;
86 }
87 
88 enum Flags {
89     kIsOpaque_Flag          = 1 << 0,
90     kHasLocalMatrix_Flag    = 1 << 1,
91 };
92 
flatten(SkWriteBuffer & buffer) const93 void SkRTShader::flatten(SkWriteBuffer& buffer) const {
94     uint32_t flags = 0;
95     if (fIsOpaque) {
96         flags |= kIsOpaque_Flag;
97     }
98     if (!this->getLocalMatrix().isIdentity()) {
99         flags |= kHasLocalMatrix_Flag;
100     }
101 
102     buffer.writeString(fSkSL.c_str());
103     if (fInputs) {
104         buffer.writeDataAsByteArray(fInputs.get());
105     } else {
106         buffer.writeByteArray(nullptr, 0);
107     }
108     buffer.write32(flags);
109     if (flags & kHasLocalMatrix_Flag) {
110         buffer.writeMatrix(this->getLocalMatrix());
111     }
112 }
113 
CreateProc(SkReadBuffer & buffer)114 sk_sp<SkFlattenable> SkRTShader::CreateProc(SkReadBuffer& buffer) {
115     // We don't have a way to ensure that indices are consistent and correct when deserializing.
116     // Perhaps we should have a hash table to map strings to indices? For now, all shaders get a
117     // new unique ID after serialization.
118     int index = new_sksl_unique_id();
119 
120     SkString sksl;
121     buffer.readString(&sksl);
122     sk_sp<SkData> inputs = buffer.readByteArrayAsData();
123     uint32_t flags = buffer.read32();
124 
125     bool isOpaque = SkToBool(flags & kIsOpaque_Flag);
126     SkMatrix localM, *localMPtr = nullptr;
127     if (flags & kHasLocalMatrix_Flag) {
128         buffer.readMatrix(&localM);
129         localMPtr = &localM;
130     }
131 
132     return sk_sp<SkFlattenable>(new SkRTShader(index, std::move(sksl), std::move(inputs),
133                                                localMPtr, isOpaque));
134 }
135 
136 #if SK_SUPPORT_GPU
asFragmentProcessor(const GrFPArgs & args) const137 std::unique_ptr<GrFragmentProcessor> SkRTShader::asFragmentProcessor(const GrFPArgs& args) const {
138     SkMatrix matrix;
139     if (!this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix)->invert(&matrix)) {
140         return nullptr;
141     }
142     return GrSkSLFP::Make(args.fContext, fUniqueID, "runtime-shader", fSkSL,
143                           fInputs->data(), fInputs->size(), SkSL::Program::kPipelineStage_Kind,
144                           &matrix);
145 }
146 #endif
147 
SkRuntimeShaderFactory(SkString sksl,bool isOpaque)148 SkRuntimeShaderFactory::SkRuntimeShaderFactory(SkString sksl, bool isOpaque)
149     : fIndex(new_sksl_unique_id())
150     , fSkSL(std::move(sksl))
151     , fIsOpaque(isOpaque) {}
152 
make(sk_sp<SkData> inputs,const SkMatrix * localMatrix)153 sk_sp<SkShader> SkRuntimeShaderFactory::make(sk_sp<SkData> inputs, const SkMatrix* localMatrix) {
154     return sk_sp<SkShader>(
155             new SkRTShader(fIndex, fSkSL, std::move(inputs), localMatrix, fIsOpaque));
156 }
157