blob: 565d7bc35a432869df3cb27e152a0cd77787c8b6 [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"
9#include "src/shaders/SkRTShader.h"
10#include "src/core/SkArenaAlloc.h"
11#include "src/core/SkRasterPipeline.h"
12#include "src/core/SkReadBuffer.h"
13#include "src/core/SkWriteBuffer.h"
14
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"
26#include "src/gpu/effects/generated/GrMixerEffect.h"
27#include "src/gpu/effects/GrSkSLFP.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
38SkRTShader::SkRTShader(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))
Mike Reed8c31f2b2019-07-16 16:50:14 -040043 , fUniqueID(new_sksl_unique_id())
Mike Reed3fd3cc92019-06-20 12:40:30 -040044 , fIsOpaque(isOpaque)
45{}
46
47bool SkRTShader::onAppendStages(const SkStageRec& rec) const {
Mike Reed3fd3cc92019-06-20 12:40:30 -040048 auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
Mike Reed8c31f2b2019-07-16 16:50:14 -040049 ctx->paintColor = rec.fPaint.getColor4f();
Mike Reed3fd3cc92019-06-20 12:40:30 -040050 ctx->inputs = fInputs->data();
51 ctx->ninputs = fInputs->size() / 4;
Mike Reed8c31f2b2019-07-16 16:50:14 -040052 ctx->shaderConvention = true;
Mike Reed3fd3cc92019-06-20 12:40:30 -040053
54 SkAutoMutexExclusive ama(fByteCodeMutex);
55 if (!fByteCode) {
56 SkSL::Compiler c;
57 auto prog = c.convertProgram(SkSL::Program::kGeneric_Kind,
58 SkSL::String(fSkSL.c_str()),
59 SkSL::Program::Settings());
60 if (c.errorCount()) {
61 SkDebugf("%s\n", c.errorText().c_str());
62 return false;
63 }
64 fByteCode = c.toByteCode(*prog);
65 if (c.errorCount()) {
66 SkDebugf("%s\n", c.errorText().c_str());
67 return false;
68 }
69 SkASSERT(fByteCode);
70 }
71 ctx->byteCode = fByteCode.get();
72 ctx->fn = ctx->byteCode->fFunctions[0].get();
73
74 rec.fPipeline->append(SkRasterPipeline::seed_shader);
Mike Reed3fd3cc92019-06-20 12:40:30 -040075 rec.fPipeline->append(SkRasterPipeline::interpreter, ctx);
76 return true;
77}
78
79enum Flags {
80 kIsOpaque_Flag = 1 << 0,
81 kHasLocalMatrix_Flag = 1 << 1,
82};
83
84void SkRTShader::flatten(SkWriteBuffer& buffer) const {
85 uint32_t flags = 0;
86 if (fIsOpaque) {
87 flags |= kIsOpaque_Flag;
88 }
89 if (!this->getLocalMatrix().isIdentity()) {
90 flags |= kHasLocalMatrix_Flag;
91 }
92
93 buffer.writeString(fSkSL.c_str());
94 if (fInputs) {
95 buffer.writeDataAsByteArray(fInputs.get());
96 } else {
97 buffer.writeByteArray(nullptr, 0);
98 }
99 buffer.write32(flags);
100 if (flags & kHasLocalMatrix_Flag) {
101 buffer.writeMatrix(this->getLocalMatrix());
102 }
103}
104
105sk_sp<SkFlattenable> SkRTShader::CreateProc(SkReadBuffer& buffer) {
106 SkString sksl;
107 buffer.readString(&sksl);
108 sk_sp<SkData> inputs = buffer.readByteArrayAsData();
109 uint32_t flags = buffer.read32();
110
111 bool isOpaque = SkToBool(flags & kIsOpaque_Flag);
112 SkMatrix localM, *localMPtr = nullptr;
113 if (flags & kHasLocalMatrix_Flag) {
114 buffer.readMatrix(&localM);
115 localMPtr = &localM;
116 }
117
118 return sk_sp<SkFlattenable>(new SkRTShader(std::move(sksl), std::move(inputs),
119 localMPtr, isOpaque));
120}
121
122sk_sp<SkShader> SkRuntimeShaderMaker(SkString sksl, sk_sp<SkData> inputs,
123 const SkMatrix* localMatrix, bool isOpaque) {
124 return sk_sp<SkShader>(new SkRTShader(std::move(sksl), std::move(inputs),
125 localMatrix, isOpaque));
126}
Mike Reed8c31f2b2019-07-16 16:50:14 -0400127
128#if SK_SUPPORT_GPU
129std::unique_ptr<GrFragmentProcessor> SkRTShader::asFragmentProcessor(const GrFPArgs& args) const {
130 return GrSkSLFP::Make(args.fContext, fUniqueID, "runtime-shader", fSkSL,
131 fInputs->data(), fInputs->size());
132}
133#endif
134