Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2018 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 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 8 | #include "src/gpu/effects/GrSkSLFP.h" |
Robert Phillips | 1efecea | 2019-02-15 16:58:40 -0500 | [diff] [blame] | 9 | |
Brian Osman | ee426f2 | 2020-01-02 11:55:24 -0500 | [diff] [blame] | 10 | #include "include/effects/SkRuntimeEffect.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 11 | #include "include/private/GrContext_Base.h" |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 12 | #include "include/private/SkSLString.h" |
Brian Osman | 1042334 | 2021-05-12 16:53:19 -0400 | [diff] [blame] | 13 | #include "src/core/SkRuntimeEffectPriv.h" |
Brian Osman | c18a645 | 2021-03-22 11:44:03 -0400 | [diff] [blame] | 14 | #include "src/core/SkVM.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 15 | #include "src/gpu/GrBaseContextPriv.h" |
Brian Salomon | f7f5433 | 2020-07-28 09:23:35 -0400 | [diff] [blame] | 16 | #include "src/gpu/GrColorInfo.h" |
Greg Daniel | 456f9b5 | 2020-03-05 19:14:18 +0000 | [diff] [blame] | 17 | #include "src/gpu/GrTexture.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 18 | #include "src/sksl/SkSLUtil.h" |
John Stiles | 3738ef5 | 2021-04-13 10:41:57 -0400 | [diff] [blame] | 19 | #include "src/sksl/codegen/SkSLPipelineStageCodeGenerator.h" |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 20 | #include "src/sksl/ir/SkSLVarDeclarations.h" |
Robert Phillips | 1efecea | 2019-02-15 16:58:40 -0500 | [diff] [blame] | 21 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 22 | #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" |
| 23 | #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
| 24 | #include "src/gpu/glsl/GrGLSLProgramBuilder.h" |
Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 25 | |
Brian Salomon | 3176e86 | 2021-08-09 11:23:04 -0400 | [diff] [blame] | 26 | class GrGLSLSkSLFP : public GrFragmentProcessor::ProgramImpl { |
Ethan Nicholas | eace935 | 2018-10-15 20:09:54 +0000 | [diff] [blame] | 27 | public: |
Ethan Nicholas | eace935 | 2018-10-15 20:09:54 +0000 | [diff] [blame] | 28 | void emitCode(EmitArgs& args) override { |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 29 | const GrSkSLFP& fp = args.fFp.cast<GrSkSLFP>(); |
| 30 | const SkSL::Program& program = *fp.fEffect->fBaseProgram; |
| 31 | |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 32 | class FPCallbacks : public SkSL::PipelineStage::Callbacks { |
| 33 | public: |
Brian Osman | ce58502 | 2021-04-15 15:39:03 -0400 | [diff] [blame] | 34 | FPCallbacks(GrGLSLSkSLFP* self, |
| 35 | EmitArgs& args, |
| 36 | const char* inputColor, |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 37 | const SkSL::Context& context, |
| 38 | const uint8_t* uniformData, |
| 39 | const GrSkSLFP::UniformFlags* uniformFlags) |
| 40 | : fSelf(self) |
| 41 | , fArgs(args) |
| 42 | , fInputColor(inputColor) |
| 43 | , fContext(context) |
| 44 | , fUniformData(uniformData) |
| 45 | , fUniformFlags(uniformFlags) {} |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 46 | |
| 47 | using String = SkSL::String; |
| 48 | |
| 49 | String declareUniform(const SkSL::VarDeclaration* decl) override { |
| 50 | const SkSL::Variable& var = decl->var(); |
| 51 | if (var.type().isOpaque()) { |
Brian Osman | 14d0096 | 2021-04-02 17:04:35 -0400 | [diff] [blame] | 52 | // Nothing to do. The only opaque types we should see are children, and those |
| 53 | // are handled specially, above. |
| 54 | SkASSERT(var.type().isEffectChild()); |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 55 | return String(var.name()); |
| 56 | } |
| 57 | |
| 58 | const SkSL::Type* type = &var.type(); |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 59 | size_t sizeInBytes = type->slotCount() * sizeof(float); |
| 60 | const float* floatData = reinterpret_cast<const float*>(fUniformData); |
| 61 | const int* intData = reinterpret_cast<const int*>(fUniformData); |
| 62 | fUniformData += sizeInBytes; |
| 63 | |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 64 | bool isArray = false; |
| 65 | if (type->isArray()) { |
| 66 | type = &type->componentType(); |
| 67 | isArray = true; |
| 68 | } |
| 69 | |
| 70 | GrSLType gpuType; |
| 71 | SkAssertResult(SkSL::type_to_grsltype(fContext, *type, &gpuType)); |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 72 | |
| 73 | if (*fUniformFlags++ & GrSkSLFP::kSpecialize_Flag) { |
| 74 | SkASSERTF(!isArray, "specializing array uniforms is not allowed"); |
| 75 | String value = GrGLSLTypeString(gpuType); |
| 76 | value.append("("); |
| 77 | |
| 78 | bool isFloat = GrSLTypeIsFloatType(gpuType); |
| 79 | size_t slots = type->slotCount(); |
| 80 | for (size_t i = 0; i < slots; ++i) { |
| 81 | value.append(isFloat ? SkSL::to_string(floatData[i]) |
| 82 | : SkSL::to_string(intData[i])); |
| 83 | value.append(","); |
| 84 | } |
| 85 | value.back() = ')'; |
| 86 | return value; |
| 87 | } |
| 88 | |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 89 | const char* uniformName = nullptr; |
| 90 | auto handle = |
| 91 | fArgs.fUniformHandler->addUniformArray(&fArgs.fFp.cast<GrSkSLFP>(), |
| 92 | kFragment_GrShaderFlag, |
| 93 | gpuType, |
| 94 | SkString(var.name()).c_str(), |
| 95 | isArray ? var.type().columns() : 0, |
| 96 | &uniformName); |
| 97 | fSelf->fUniformHandles.push_back(handle); |
| 98 | return String(uniformName); |
| 99 | } |
| 100 | |
Brian Osman | 55761ae | 2021-02-09 16:52:53 -0500 | [diff] [blame] | 101 | String getMangledName(const char* name) override { |
| 102 | return String(fArgs.fFragBuilder->getMangledFunctionName(name).c_str()); |
| 103 | } |
| 104 | |
| 105 | void defineFunction(const char* decl, const char* body, bool isMain) override { |
| 106 | if (isMain) { |
| 107 | fArgs.fFragBuilder->codeAppend(body); |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 108 | } else { |
Brian Osman | 55761ae | 2021-02-09 16:52:53 -0500 | [diff] [blame] | 109 | fArgs.fFragBuilder->emitFunction(decl, body); |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 110 | } |
| 111 | } |
| 112 | |
Brian Osman | 8e756f3 | 2021-02-10 10:19:27 -0500 | [diff] [blame] | 113 | void defineStruct(const char* definition) override { |
| 114 | fArgs.fFragBuilder->definitionAppend(definition); |
| 115 | } |
| 116 | |
Brian Osman | 5e603c3 | 2021-02-17 15:39:06 -0500 | [diff] [blame] | 117 | void declareGlobal(const char* declaration) override { |
| 118 | fArgs.fFragBuilder->definitionAppend(declaration); |
| 119 | } |
| 120 | |
John Stiles | d9a56b9 | 2021-07-23 15:50:39 -0400 | [diff] [blame] | 121 | String sampleShader(int index, String coords) override { |
Brian Osman | 4d57111 | 2021-04-27 09:10:10 -0400 | [diff] [blame] | 122 | // If the child was sampled using the coords passed to main (and they are never |
| 123 | // modified), then we will have marked the child as PassThrough. The code generator |
| 124 | // doesn't know that, and still supplies coords. Inside invokeChild, we assert that |
| 125 | // any coords passed for a PassThrough child match args.fSampleCoords exactly. |
| 126 | // |
| 127 | // Normally, this is valid. Here, we *copied* the sample coords to a local variable |
| 128 | // (so that they're mutable in the runtime effect SkSL). Thus, the coords string we |
| 129 | // get here is the name of the local copy, and fSampleCoords still points to the |
| 130 | // unmodified original (which might be a varying, for example). |
| 131 | // To prevent the assert, we pass the empty string in this case. Note that for |
| 132 | // children sampled like this, invokeChild doesn't even use the coords parameter, |
| 133 | // except for that assert. |
| 134 | const GrFragmentProcessor* child = fArgs.fFp.childProcessor(index); |
Brian Osman | 56b6107 | 2021-06-29 13:12:40 -0400 | [diff] [blame] | 135 | if (child && child->sampleUsage().isPassThrough()) { |
Brian Osman | 4d57111 | 2021-04-27 09:10:10 -0400 | [diff] [blame] | 136 | coords.clear(); |
| 137 | } |
John Stiles | d9a56b9 | 2021-07-23 15:50:39 -0400 | [diff] [blame] | 138 | return String(fSelf->invokeChild(index, fInputColor, fArgs, coords).c_str()); |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 139 | } |
| 140 | |
John Stiles | 8050a4b | 2021-07-23 15:50:20 -0400 | [diff] [blame] | 141 | String sampleColorFilter(int index, String color) override { |
| 142 | return String(fSelf->invokeChild(index, |
| 143 | color.empty() ? fInputColor : color.c_str(), |
| 144 | fArgs) |
| 145 | .c_str()); |
| 146 | } |
| 147 | |
John Stiles | 2955c26 | 2021-07-23 15:51:05 -0400 | [diff] [blame] | 148 | String sampleBlender(int index, String src, String dst) override { |
John Stiles | ce9a5c9 | 2021-07-30 11:20:19 -0400 | [diff] [blame] | 149 | if (!fSelf->childProcessor(index)) { |
| 150 | return String::printf("blend_src_over(%s, %s)", src.c_str(), dst.c_str()); |
| 151 | } |
| 152 | return String(fSelf->invokeChild(index, src.c_str(), dst.c_str(), fArgs).c_str()); |
John Stiles | 2955c26 | 2021-07-23 15:51:05 -0400 | [diff] [blame] | 153 | } |
| 154 | |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 155 | GrGLSLSkSLFP* fSelf; |
| 156 | EmitArgs& fArgs; |
| 157 | const char* fInputColor; |
| 158 | const SkSL::Context& fContext; |
| 159 | const uint8_t* fUniformData; |
| 160 | const GrSkSLFP::UniformFlags* fUniformFlags; |
| 161 | int fUniformIndex = 0; |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 162 | }; |
| 163 | |
Brian Osman | b2cb817 | 2021-06-15 14:36:17 -0400 | [diff] [blame] | 164 | // If we have an input child, we invoke it now, and make the result of that be the "input |
| 165 | // color" for all other purposes later (eg, the default passed via sample calls, etc.) |
| 166 | if (fp.fInputChildIndex >= 0) { |
| 167 | args.fFragBuilder->codeAppendf("%s = %s;\n", |
| 168 | args.fInputColor, |
| 169 | this->invokeChild(fp.fInputChildIndex, args).c_str()); |
| 170 | } |
| 171 | |
John Stiles | 21c2af2 | 2021-07-29 11:42:55 -0400 | [diff] [blame] | 172 | if (fp.fEffect->allowBlender()) { |
| 173 | // If we have an dest-color child, we invoke it now, and make the result of that be the |
| 174 | // "dest color" for all other purposes later. |
| 175 | if (fp.fDestColorChildIndex >= 0) { |
| 176 | args.fFragBuilder->codeAppendf( |
| 177 | "%s = %s;\n", |
| 178 | args.fDestColor, |
| 179 | this->invokeChild(fp.fDestColorChildIndex, args.fDestColor, args).c_str()); |
| 180 | } |
| 181 | } else { |
| 182 | // We're not making a blender, so we don't expect a dest-color child FP to exist. |
| 183 | SkASSERT(fp.fDestColorChildIndex < 0); |
| 184 | } |
| 185 | |
Brian Osman | ce58502 | 2021-04-15 15:39:03 -0400 | [diff] [blame] | 186 | // Snap off a global copy of the input color at the start of main. We need this when |
| 187 | // we call child processors (particularly from helper functions, which can't "see" the |
| 188 | // parameter to main). Even from within main, if the code mutates the parameter, calls to |
| 189 | // sample should still be passing the original color (by default). |
Brian Osman | 04d79fc | 2021-07-02 13:25:35 -0400 | [diff] [blame] | 190 | SkString inputColorName; |
| 191 | if (fp.fEffect->samplesOutsideMain()) { |
| 192 | GrShaderVar inputColorCopy(args.fFragBuilder->getMangledFunctionName("inColor"), |
| 193 | kHalf4_GrSLType); |
| 194 | args.fFragBuilder->declareGlobal(inputColorCopy); |
| 195 | inputColorName = inputColorCopy.getName(); |
| 196 | args.fFragBuilder->codeAppendf("%s = %s;\n", inputColorName.c_str(), args.fInputColor); |
| 197 | } else { |
| 198 | inputColorName = args.fFragBuilder->newTmpVarName("inColor"); |
| 199 | args.fFragBuilder->codeAppendf( |
| 200 | "half4 %s = %s;\n", inputColorName.c_str(), args.fInputColor); |
| 201 | } |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 202 | |
Brian Osman | 8cdf28f | 2021-05-24 09:52:39 -0400 | [diff] [blame] | 203 | // Copy the incoming coords to a local variable. Code in main might modify the coords |
| 204 | // parameter. fSampleCoord could be a varying, so writes to it would be illegal. |
John Stiles | 9b170c6 | 2021-06-18 10:14:14 -0400 | [diff] [blame] | 205 | const char* coords = "float2(0)"; |
| 206 | SkString coordsVarName; |
Brian Salomon | 66b500a | 2021-08-02 12:37:14 -0400 | [diff] [blame] | 207 | if (fp.usesSampleCoordsDirectly()) { |
John Stiles | 9b170c6 | 2021-06-18 10:14:14 -0400 | [diff] [blame] | 208 | coordsVarName = args.fFragBuilder->newTmpVarName("coords"); |
| 209 | coords = coordsVarName.c_str(); |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 210 | args.fFragBuilder->codeAppendf("float2 %s = %s;\n", coords, args.fSampleCoord); |
Brian Osman | b4ce944 | 2020-11-11 09:18:02 -0500 | [diff] [blame] | 211 | } |
Brian Osman | 690b6f3 | 2021-02-05 16:30:34 -0500 | [diff] [blame] | 212 | |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 213 | FPCallbacks callbacks(this, |
| 214 | args, |
Brian Osman | 04d79fc | 2021-07-02 13:25:35 -0400 | [diff] [blame] | 215 | inputColorName.c_str(), |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 216 | *program.fContext, |
| 217 | fp.uniformData(), |
| 218 | fp.uniformFlags()); |
| 219 | SkSL::PipelineStage::ConvertProgram( |
John Stiles | 21c2af2 | 2021-07-29 11:42:55 -0400 | [diff] [blame] | 220 | program, coords, args.fInputColor, args.fDestColor, &callbacks); |
Ethan Nicholas | ce00811 | 2018-08-30 09:19:50 -0400 | [diff] [blame] | 221 | } |
| 222 | |
Ethan Nicholas | eace935 | 2018-10-15 20:09:54 +0000 | [diff] [blame] | 223 | void onSetData(const GrGLSLProgramDataManager& pdman, |
| 224 | const GrFragmentProcessor& _proc) override { |
Brian Osman | d18967c | 2021-04-01 09:56:07 -0400 | [diff] [blame] | 225 | using Type = SkRuntimeEffect::Uniform::Type; |
Brian Osman | d927bd2 | 2019-12-18 11:23:12 -0500 | [diff] [blame] | 226 | size_t uniIndex = 0; |
Ethan Nicholas | eace935 | 2018-10-15 20:09:54 +0000 | [diff] [blame] | 227 | const GrSkSLFP& outer = _proc.cast<GrSkSLFP>(); |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 228 | const uint8_t* uniformData = outer.uniformData(); |
| 229 | const GrSkSLFP::UniformFlags* uniformFlags = outer.uniformFlags(); |
Brian Osman | a4b9169 | 2020-08-10 14:26:16 -0400 | [diff] [blame] | 230 | for (const auto& v : outer.fEffect->uniforms()) { |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 231 | if (*uniformFlags++ & GrSkSLFP::kSpecialize_Flag) { |
| 232 | continue; |
| 233 | } |
Brian Osman | d18967c | 2021-04-01 09:56:07 -0400 | [diff] [blame] | 234 | const UniformHandle handle = fUniformHandles[uniIndex++]; |
| 235 | auto floatData = [=] { return SkTAddOffset<const float>(uniformData, v.offset); }; |
| 236 | auto intData = [=] { return SkTAddOffset<const int>(uniformData, v.offset); }; |
Brian Osman | d76d186 | 2021-02-03 14:48:41 -0500 | [diff] [blame] | 237 | switch (v.type) { |
Brian Osman | d18967c | 2021-04-01 09:56:07 -0400 | [diff] [blame] | 238 | case Type::kFloat: pdman.set1fv(handle, v.count, floatData()); break; |
| 239 | case Type::kFloat2: pdman.set2fv(handle, v.count, floatData()); break; |
| 240 | case Type::kFloat3: pdman.set3fv(handle, v.count, floatData()); break; |
| 241 | case Type::kFloat4: pdman.set4fv(handle, v.count, floatData()); break; |
| 242 | |
| 243 | case Type::kFloat2x2: pdman.setMatrix2fv(handle, v.count, floatData()); break; |
| 244 | case Type::kFloat3x3: pdman.setMatrix3fv(handle, v.count, floatData()); break; |
| 245 | case Type::kFloat4x4: pdman.setMatrix4fv(handle, v.count, floatData()); break; |
| 246 | |
| 247 | case Type::kInt: pdman.set1iv(handle, v.count, intData()); break; |
| 248 | case Type::kInt2: pdman.set2iv(handle, v.count, intData()); break; |
| 249 | case Type::kInt3: pdman.set3iv(handle, v.count, intData()); break; |
| 250 | case Type::kInt4: pdman.set4iv(handle, v.count, intData()); break; |
| 251 | |
Ethan Nicholas | c1c686b | 2019-04-02 17:30:23 -0400 | [diff] [blame] | 252 | default: |
Brian Osman | d927bd2 | 2019-12-18 11:23:12 -0500 | [diff] [blame] | 253 | SkDEBUGFAIL("Unsupported uniform type"); |
| 254 | break; |
Ethan Nicholas | 222e275 | 2018-10-11 11:21:34 -0400 | [diff] [blame] | 255 | } |
Ethan Nicholas | 222e275 | 2018-10-11 11:21:34 -0400 | [diff] [blame] | 256 | } |
| 257 | } |
Ethan Nicholas | eace935 | 2018-10-15 20:09:54 +0000 | [diff] [blame] | 258 | |
Ethan Nicholas | eace935 | 2018-10-15 20:09:54 +0000 | [diff] [blame] | 259 | std::vector<UniformHandle> fUniformHandles; |
| 260 | }; |
| 261 | |
Brian Osman | b2cb817 | 2021-06-15 14:36:17 -0400 | [diff] [blame] | 262 | std::unique_ptr<GrSkSLFP> GrSkSLFP::MakeWithData( |
| 263 | sk_sp<SkRuntimeEffect> effect, |
| 264 | const char* name, |
| 265 | std::unique_ptr<GrFragmentProcessor> inputFP, |
John Stiles | a664859 | 2021-07-19 18:11:09 -0400 | [diff] [blame] | 266 | std::unique_ptr<GrFragmentProcessor> destColorFP, |
Brian Osman | b2cb817 | 2021-06-15 14:36:17 -0400 | [diff] [blame] | 267 | sk_sp<SkData> uniforms, |
| 268 | SkSpan<std::unique_ptr<GrFragmentProcessor>> childFPs) { |
Brian Osman | a4b9169 | 2020-08-10 14:26:16 -0400 | [diff] [blame] | 269 | if (uniforms->size() != effect->uniformSize()) { |
Brian Osman | 9bfd595 | 2020-02-05 10:51:44 -0500 | [diff] [blame] | 270 | return nullptr; |
| 271 | } |
Brian Osman | 681e409 | 2021-06-03 14:26:07 -0400 | [diff] [blame] | 272 | size_t uniformSize = uniforms->size(); |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 273 | size_t uniformFlagSize = effect->uniforms().count() * sizeof(UniformFlags); |
| 274 | std::unique_ptr<GrSkSLFP> fp(new (uniformSize + uniformFlagSize) |
John Stiles | 02b6f6f | 2021-07-30 11:06:55 -0400 | [diff] [blame] | 275 | GrSkSLFP(std::move(effect), name, OptFlags::kNone)); |
Brian Osman | 1f5ee0d | 2021-06-10 14:40:40 -0400 | [diff] [blame] | 276 | sk_careful_memcpy(fp->uniformData(), uniforms->data(), uniformSize); |
Brian Osman | b2cb817 | 2021-06-15 14:36:17 -0400 | [diff] [blame] | 277 | for (auto& childFP : childFPs) { |
Brian Osman | 9204ca6 | 2021-06-25 12:35:16 -0400 | [diff] [blame] | 278 | fp->addChild(std::move(childFP), /*mergeOptFlags=*/true); |
Brian Osman | b2cb817 | 2021-06-15 14:36:17 -0400 | [diff] [blame] | 279 | } |
| 280 | if (inputFP) { |
| 281 | fp->setInput(std::move(inputFP)); |
| 282 | } |
John Stiles | a664859 | 2021-07-19 18:11:09 -0400 | [diff] [blame] | 283 | if (destColorFP) { |
| 284 | fp->setDestColorFP(std::move(destColorFP)); |
| 285 | } |
Brian Osman | 1f5ee0d | 2021-06-10 14:40:40 -0400 | [diff] [blame] | 286 | return fp; |
Ethan Nicholas | a70693b | 2019-03-04 13:07:36 -0500 | [diff] [blame] | 287 | } |
| 288 | |
Brian Osman | 171fba7 | 2021-06-16 17:10:21 -0400 | [diff] [blame] | 289 | GrSkSLFP::GrSkSLFP(sk_sp<SkRuntimeEffect> effect, const char* name, OptFlags optFlags) |
Brian Osman | e384c06 | 2021-06-04 14:09:51 -0400 | [diff] [blame] | 290 | : INHERITED(kGrSkSLFP_ClassID, |
Brian Osman | 171fba7 | 2021-06-16 17:10:21 -0400 | [diff] [blame] | 291 | static_cast<OptimizationFlags>(optFlags) | |
| 292 | (effect->getFilterColorProgram() |
| 293 | ? kConstantOutputForConstantInput_OptimizationFlag |
| 294 | : kNone_OptimizationFlags)) |
Brian Osman | e384c06 | 2021-06-04 14:09:51 -0400 | [diff] [blame] | 295 | , fEffect(std::move(effect)) |
| 296 | , fName(name) |
Brian Osman | b2cb817 | 2021-06-15 14:36:17 -0400 | [diff] [blame] | 297 | , fUniformSize(SkToU32(fEffect->uniformSize())) { |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 298 | memset(this->uniformFlags(), 0, fEffect->uniforms().count() * sizeof(UniformFlags)); |
Brian Osman | e384c06 | 2021-06-04 14:09:51 -0400 | [diff] [blame] | 299 | if (fEffect->usesSampleCoords()) { |
| 300 | this->setUsesSampleCoordsDirectly(); |
| 301 | } |
John Stiles | 02b6f6f | 2021-07-30 11:06:55 -0400 | [diff] [blame] | 302 | if (fEffect->allowBlender()) { |
| 303 | this->setIsBlendFunction(); |
| 304 | } |
Brian Osman | e384c06 | 2021-06-04 14:09:51 -0400 | [diff] [blame] | 305 | } |
| 306 | |
Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 307 | GrSkSLFP::GrSkSLFP(const GrSkSLFP& other) |
John Stiles | 307f8f5 | 2021-08-09 15:36:59 -0400 | [diff] [blame^] | 308 | : INHERITED(other) |
Brian Osman | 7b1678a | 2019-12-16 09:17:25 -0500 | [diff] [blame] | 309 | , fEffect(other.fEffect) |
Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 310 | , fName(other.fName) |
Brian Osman | b2cb817 | 2021-06-15 14:36:17 -0400 | [diff] [blame] | 311 | , fUniformSize(other.fUniformSize) |
| 312 | , fInputChildIndex(other.fInputChildIndex) { |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 313 | sk_careful_memcpy(this->uniformFlags(), |
| 314 | other.uniformFlags(), |
| 315 | fEffect->uniforms().count() * sizeof(UniformFlags)); |
Brian Osman | 681e409 | 2021-06-03 14:26:07 -0400 | [diff] [blame] | 316 | sk_careful_memcpy(this->uniformData(), other.uniformData(), fUniformSize); |
Ethan Nicholas | eace935 | 2018-10-15 20:09:54 +0000 | [diff] [blame] | 317 | } |
Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 318 | |
Brian Osman | 9204ca6 | 2021-06-25 12:35:16 -0400 | [diff] [blame] | 319 | void GrSkSLFP::addChild(std::unique_ptr<GrFragmentProcessor> child, bool mergeOptFlags) { |
Brian Osman | b2cb817 | 2021-06-15 14:36:17 -0400 | [diff] [blame] | 320 | SkASSERTF(fInputChildIndex == -1, "all addChild calls must happen before setInput"); |
John Stiles | a664859 | 2021-07-19 18:11:09 -0400 | [diff] [blame] | 321 | SkASSERTF(fDestColorChildIndex == -1, "all addChild calls must happen before setDestColorFP"); |
Brian Osman | be1b837 | 2020-06-18 13:40:26 -0400 | [diff] [blame] | 322 | int childIndex = this->numChildProcessors(); |
Brian Osman | 1298bc4 | 2020-06-30 13:39:35 -0400 | [diff] [blame] | 323 | SkASSERT((size_t)childIndex < fEffect->fSampleUsages.size()); |
Brian Osman | 9204ca6 | 2021-06-25 12:35:16 -0400 | [diff] [blame] | 324 | if (mergeOptFlags) { |
| 325 | this->mergeOptimizationFlags(ProcessorOptimizationFlags(child.get())); |
| 326 | } |
Brian Osman | 1298bc4 | 2020-06-30 13:39:35 -0400 | [diff] [blame] | 327 | this->registerChild(std::move(child), fEffect->fSampleUsages[childIndex]); |
Ethan Nicholas | ce00811 | 2018-08-30 09:19:50 -0400 | [diff] [blame] | 328 | } |
| 329 | |
Brian Osman | b2cb817 | 2021-06-15 14:36:17 -0400 | [diff] [blame] | 330 | void GrSkSLFP::setInput(std::unique_ptr<GrFragmentProcessor> input) { |
| 331 | SkASSERTF(fInputChildIndex == -1, "setInput should not be called more than once"); |
| 332 | fInputChildIndex = this->numChildProcessors(); |
John Stiles | a664859 | 2021-07-19 18:11:09 -0400 | [diff] [blame] | 333 | SkASSERT((size_t)fInputChildIndex >= fEffect->fSampleUsages.size()); |
Brian Osman | b2cb817 | 2021-06-15 14:36:17 -0400 | [diff] [blame] | 334 | this->mergeOptimizationFlags(ProcessorOptimizationFlags(input.get())); |
| 335 | this->registerChild(std::move(input), SkSL::SampleUsage::PassThrough()); |
| 336 | } |
| 337 | |
John Stiles | a664859 | 2021-07-19 18:11:09 -0400 | [diff] [blame] | 338 | void GrSkSLFP::setDestColorFP(std::unique_ptr<GrFragmentProcessor> destColorFP) { |
| 339 | SkASSERTF(fEffect->allowBlender(), "dest colors are only used by blend effects"); |
| 340 | SkASSERTF(fDestColorChildIndex == -1, "setDestColorFP should not be called more than once"); |
| 341 | fDestColorChildIndex = this->numChildProcessors(); |
| 342 | SkASSERT((size_t)fDestColorChildIndex >= fEffect->fSampleUsages.size()); |
| 343 | this->mergeOptimizationFlags(ProcessorOptimizationFlags(destColorFP.get())); |
| 344 | this->registerChild(std::move(destColorFP), SkSL::SampleUsage::PassThrough()); |
| 345 | } |
| 346 | |
Brian Salomon | 3176e86 | 2021-08-09 11:23:04 -0400 | [diff] [blame] | 347 | std::unique_ptr<GrFragmentProcessor::ProgramImpl> GrSkSLFP::onMakeProgramImpl() const { |
Brian Salomon | 18ab203 | 2021-02-23 10:07:05 -0500 | [diff] [blame] | 348 | return std::make_unique<GrGLSLSkSLFP>(); |
Greg Daniel | f410794 | 2019-12-12 01:02:48 +0000 | [diff] [blame] | 349 | } |
| 350 | |
Brian Salomon | 13b2873 | 2021-08-06 15:33:58 -0400 | [diff] [blame] | 351 | void GrSkSLFP::onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { |
Brian Osman | a4b9169 | 2020-08-10 14:26:16 -0400 | [diff] [blame] | 352 | // In the unlikely event of a hash collision, we also include the uniform size in the key. |
Brian Osman | 3225306 | 2020-02-05 11:37:08 -0500 | [diff] [blame] | 353 | // That ensures that we will (at worst) use the wrong program, but one that expects the same |
Brian Osman | a4b9169 | 2020-08-10 14:26:16 -0400 | [diff] [blame] | 354 | // amount of uniform data. |
Brian Osman | 3225306 | 2020-02-05 11:37:08 -0500 | [diff] [blame] | 355 | b->add32(fEffect->hash()); |
Brian Osman | b2cb817 | 2021-06-15 14:36:17 -0400 | [diff] [blame] | 356 | b->add32(fUniformSize); |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 357 | |
| 358 | const UniformFlags* flags = this->uniformFlags(); |
| 359 | const uint8_t* uniformData = this->uniformData(); |
| 360 | size_t uniformCount = fEffect->uniforms().count(); |
| 361 | auto iter = fEffect->uniforms().begin(); |
| 362 | |
Brian Osman | d02d4eb | 2021-06-23 11:33:16 -0400 | [diff] [blame] | 363 | for (size_t i = 0; i < uniformCount; ++i, ++iter) { |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 364 | bool specialize = flags[i] & kSpecialize_Flag; |
| 365 | b->addBool(specialize, "specialize"); |
| 366 | if (specialize) { |
| 367 | b->addBytes(iter->sizeInBytes(), uniformData + iter->offset, iter->name.c_str()); |
| 368 | } |
| 369 | } |
Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 370 | } |
| 371 | |
| 372 | bool GrSkSLFP::onIsEqual(const GrFragmentProcessor& other) const { |
| 373 | const GrSkSLFP& sk = other.cast<GrSkSLFP>(); |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 374 | const size_t uniformFlagSize = fEffect->uniforms().count() * sizeof(UniformFlags); |
Brian Osman | 681e409 | 2021-06-03 14:26:07 -0400 | [diff] [blame] | 375 | return fEffect->hash() == sk.fEffect->hash() && |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 376 | fEffect->uniforms().count() == sk.fEffect->uniforms().count() && |
Brian Osman | 681e409 | 2021-06-03 14:26:07 -0400 | [diff] [blame] | 377 | fUniformSize == sk.fUniformSize && |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 378 | !sk_careful_memcmp( |
| 379 | this->uniformData(), sk.uniformData(), fUniformSize + uniformFlagSize); |
Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 380 | } |
| 381 | |
| 382 | std::unique_ptr<GrFragmentProcessor> GrSkSLFP::clone() const { |
Brian Osman | 70ae91f | 2021-06-10 14:27:53 -0400 | [diff] [blame] | 383 | return std::unique_ptr<GrFragmentProcessor>(new (UniformPayloadSize(fEffect.get())) |
| 384 | GrSkSLFP(*this)); |
Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 385 | } |
| 386 | |
Brian Osman | c18a645 | 2021-03-22 11:44:03 -0400 | [diff] [blame] | 387 | SkPMColor4f GrSkSLFP::constantOutputForConstantInput(const SkPMColor4f& inputColor) const { |
Brian Osman | 1042334 | 2021-05-12 16:53:19 -0400 | [diff] [blame] | 388 | const SkFilterColorProgram* program = fEffect->getFilterColorProgram(); |
Brian Osman | c9125aa | 2021-04-21 09:57:19 -0400 | [diff] [blame] | 389 | SkASSERT(program); |
Brian Osman | c18a645 | 2021-03-22 11:44:03 -0400 | [diff] [blame] | 390 | |
Brian Osman | 1042334 | 2021-05-12 16:53:19 -0400 | [diff] [blame] | 391 | auto evalChild = [&](int index, SkPMColor4f color) { |
| 392 | return ConstantOutputForConstantInput(this->childProcessor(index), color); |
| 393 | }; |
Brian Osman | c18a645 | 2021-03-22 11:44:03 -0400 | [diff] [blame] | 394 | |
Brian Osman | b2cb817 | 2021-06-15 14:36:17 -0400 | [diff] [blame] | 395 | SkPMColor4f color = (fInputChildIndex >= 0) |
| 396 | ? ConstantOutputForConstantInput( |
| 397 | this->childProcessor(fInputChildIndex), inputColor) |
| 398 | : inputColor; |
| 399 | return program->eval(color, this->uniformData(), evalChild); |
Brian Osman | c18a645 | 2021-03-22 11:44:03 -0400 | [diff] [blame] | 400 | } |
| 401 | |
Robert Phillips | 7f11fb5 | 2019-12-03 13:35:19 -0500 | [diff] [blame] | 402 | /**************************************************************************************************/ |
Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 403 | |
| 404 | GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSkSLFP); |
| 405 | |
| 406 | #if GR_TEST_UTILS |
| 407 | |
Mike Klein | a73819b | 2020-04-17 08:26:30 -0500 | [diff] [blame] | 408 | #include "include/effects/SkOverdrawColorFilter.h" |
Mike Reed | b11e627 | 2020-06-24 16:56:33 -0400 | [diff] [blame] | 409 | #include "src/core/SkColorFilterBase.h" |
Ethan Nicholas | 78aceb2 | 2018-08-31 16:13:58 -0400 | [diff] [blame] | 410 | |
Ethan Nicholas | 78aceb2 | 2018-08-31 16:13:58 -0400 | [diff] [blame] | 411 | extern const char* SKSL_OVERDRAW_SRC; |
Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 412 | |
Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 413 | std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d) { |
John Stiles | a9c9b53 | 2020-07-09 17:13:13 -0400 | [diff] [blame] | 414 | SkColor colors[SkOverdrawColorFilter::kNumColors]; |
| 415 | for (SkColor& c : colors) { |
| 416 | c = d->fRandom->nextU(); |
Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 417 | } |
John Stiles | a9c9b53 | 2020-07-09 17:13:13 -0400 | [diff] [blame] | 418 | auto filter = SkOverdrawColorFilter::MakeWithSkColors(colors); |
| 419 | auto [success, fp] = as_CFB(filter)->asFragmentProcessor(/*inputFP=*/nullptr, d->context(), |
| 420 | GrColorInfo{}); |
| 421 | SkASSERT(success); |
| 422 | return std::move(fp); |
Ethan Nicholas | 0054311 | 2018-07-31 09:44:36 -0400 | [diff] [blame] | 423 | } |
| 424 | |
| 425 | #endif |