blob: 34dc5a47177416208c656c1eda653dc4ce3435d1 [file] [log] [blame]
Mike Reed3fd3cc92019-06-20 12:40:30 -04001/*
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"
Mike Reed3fd3cc92019-06-20 12:40:30 -04009#include "src/core/SkArenaAlloc.h"
10#include "src/core/SkRasterPipeline.h"
11#include "src/core/SkReadBuffer.h"
12#include "src/core/SkWriteBuffer.h"
Mike Klein52337de2019-07-25 09:00:52 -050013#include "src/shaders/SkRTShader.h"
Mike Reed3fd3cc92019-06-20 12:40:30 -040014
Mike Reed8c31f2b2019-07-16 16:50:14 -040015#include "src/sksl/SkSLByteCode.h"
16#include "src/sksl/SkSLCompiler.h"
17
Mike Reed3fd3cc92019-06-20 12:40:30 -040018#if SK_SUPPORT_GPU
Mike Reed8c31f2b2019-07-16 16:50:14 -040019#include "include/private/GrRecordingContext.h"
20#include "src/gpu/GrCaps.h"
21#include "src/gpu/GrColorSpaceInfo.h"
22#include "src/gpu/GrRecordingContextPriv.h"
23#include "src/gpu/SkGr.h"
24
Mike Reed3fd3cc92019-06-20 12:40:30 -040025#include "src/gpu/GrFragmentProcessor.h"
Mike Reed3fd3cc92019-06-20 12:40:30 -040026#include "src/gpu/effects/GrSkSLFP.h"
Mike Klein52337de2019-07-25 09:00:52 -050027#include "src/gpu/effects/generated/GrMixerEffect.h"
Mike Reed3fd3cc92019-06-20 12:40:30 -040028
Mike Reed8c31f2b2019-07-16 16:50:14 -040029static inline uint32_t new_sksl_unique_id() {
30 return GrSkSLFP::NewIndex();
31}
32#else
33static inline uint32_t new_sksl_unique_id() {
34 return 0; // not used w/o GPU
35}
36#endif
Mike Reed3fd3cc92019-06-20 12:40:30 -040037
Brian Osman7e16b582019-08-20 16:56:40 -040038SkRTShader::SkRTShader(int index, SkString sksl, sk_sp<SkData> inputs, const SkMatrix* localMatrix,
Mike Reed3fd3cc92019-06-20 12:40:30 -040039 bool isOpaque)
40 : SkShaderBase(localMatrix)
41 , fSkSL(std::move(sksl))
42 , fInputs(std::move(inputs))
Brian Osman7e16b582019-08-20 16:56:40 -040043 , fUniqueID(index)
Mike Reed3fd3cc92019-06-20 12:40:30 -040044 , fIsOpaque(isOpaque)
45{}
46
47bool SkRTShader::onAppendStages(const SkStageRec& rec) const {
Brian Osman3b1e4c22019-08-12 15:12:14 -040048 SkMatrix inverse;
49 if (!this->computeTotalInverse(rec.fCTM, rec.fLocalM, &inverse)) {
50 return false;
51 }
52
Mike Reed3fd3cc92019-06-20 12:40:30 -040053 auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
Mike Reed8c31f2b2019-07-16 16:50:14 -040054 ctx->paintColor = rec.fPaint.getColor4f();
Mike Reed3fd3cc92019-06-20 12:40:30 -040055 ctx->inputs = fInputs->data();
56 ctx->ninputs = fInputs->size() / 4;
Mike Reed8c31f2b2019-07-16 16:50:14 -040057 ctx->shaderConvention = true;
Mike Reed3fd3cc92019-06-20 12:40:30 -040058
59 SkAutoMutexExclusive ama(fByteCodeMutex);
60 if (!fByteCode) {
61 SkSL::Compiler c;
62 auto prog = c.convertProgram(SkSL::Program::kGeneric_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);
Mike Reedfd986282019-07-17 13:16:01 -040075 if (!fByteCode->getFunction("main")) {
76 return false;
77 }
Mike Reed3fd3cc92019-06-20 12:40:30 -040078 }
79 ctx->byteCode = fByteCode.get();
Mike Reedfd986282019-07-17 13:16:01 -040080 ctx->fn = ctx->byteCode->getFunction("main");
Mike Reed3fd3cc92019-06-20 12:40:30 -040081
82 rec.fPipeline->append(SkRasterPipeline::seed_shader);
Brian Osman3b1e4c22019-08-12 15:12:14 -040083 rec.fPipeline->append_matrix(rec.fAlloc, inverse);
Mike Reed3fd3cc92019-06-20 12:40:30 -040084 rec.fPipeline->append(SkRasterPipeline::interpreter, ctx);
85 return true;
86}
87
88enum Flags {
89 kIsOpaque_Flag = 1 << 0,
90 kHasLocalMatrix_Flag = 1 << 1,
91};
92
93void 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
114sk_sp<SkFlattenable> SkRTShader::CreateProc(SkReadBuffer& buffer) {
Brian Osman7e16b582019-08-20 16:56:40 -0400115 // 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
Mike Reed3fd3cc92019-06-20 12:40:30 -0400120 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
Brian Osman7e16b582019-08-20 16:56:40 -0400132 return sk_sp<SkFlattenable>(new SkRTShader(index, std::move(sksl), std::move(inputs),
Mike Reed3fd3cc92019-06-20 12:40:30 -0400133 localMPtr, isOpaque));
134}
135
Mike Reed8c31f2b2019-07-16 16:50:14 -0400136#if SK_SUPPORT_GPU
137std::unique_ptr<GrFragmentProcessor> SkRTShader::asFragmentProcessor(const GrFPArgs& args) const {
Brian Osman3b1e4c22019-08-12 15:12:14 -0400138 SkMatrix matrix;
139 if (!this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix)->invert(&matrix)) {
140 return nullptr;
141 }
Mike Reed8c31f2b2019-07-16 16:50:14 -0400142 return GrSkSLFP::Make(args.fContext, fUniqueID, "runtime-shader", fSkSL,
Brian Osman3b1e4c22019-08-12 15:12:14 -0400143 fInputs->data(), fInputs->size(), SkSL::Program::kPipelineStage_Kind,
144 &matrix);
Mike Reed8c31f2b2019-07-16 16:50:14 -0400145}
146#endif
Brian Osman7e16b582019-08-20 16:56:40 -0400147
148SkRuntimeShaderFactory::SkRuntimeShaderFactory(SkString sksl, bool isOpaque)
149 : fIndex(new_sksl_unique_id())
150 , fSkSL(std::move(sksl))
151 , fIsOpaque(isOpaque) {}
152
153sk_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}