diff options
author | Ethan Nicholas <ethannicholas@google.com> | 2018-07-12 14:02:00 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-07-19 19:00:55 +0000 |
commit | 97ae0c89025dfd791047f5701e57d58da37c125c (patch) | |
tree | d944775c2c88dd36d5e40fb6c1bae5c7c2376e3b /src/gpu/effects | |
parent | 310f44d3d5298becdd8ab235af29789f6ed769b5 (diff) |
Revert "Revert "added GrSkSLFP and converted DitherEffect to use it""
This reverts commit f2030783094e502fb74221077a5ee7cb41287fe4.
Bug: skia:
Change-Id: Icaaa8b3ea652a8f126bfbcc788a360493a7ebe3e
Reviewed-on: https://skia-review.googlesource.com/137391
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'src/gpu/effects')
-rw-r--r-- | src/gpu/effects/GrDitherEffect.cpp | 75 | ||||
-rw-r--r-- | src/gpu/effects/GrDitherEffect.fp | 85 | ||||
-rw-r--r-- | src/gpu/effects/GrDitherEffect.h | 67 | ||||
-rw-r--r-- | src/gpu/effects/GrRectBlurEffect.cpp | 34 | ||||
-rw-r--r-- | src/gpu/effects/GrSkSLFP.cpp | 268 | ||||
-rw-r--r-- | src/gpu/effects/GrSkSLFP.h | 147 |
6 files changed, 432 insertions, 244 deletions
diff --git a/src/gpu/effects/GrDitherEffect.cpp b/src/gpu/effects/GrDitherEffect.cpp deleted file mode 100644 index 17c8776524..0000000000 --- a/src/gpu/effects/GrDitherEffect.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/************************************************************************************************** - *** This file was autogenerated from GrDitherEffect.fp; do not modify. - **************************************************************************************************/ -#include "GrDitherEffect.h" -#include "glsl/GrGLSLFragmentProcessor.h" -#include "glsl/GrGLSLFragmentShaderBuilder.h" -#include "glsl/GrGLSLProgramBuilder.h" -#include "GrTexture.h" -#include "SkSLCPP.h" -#include "SkSLUtil.h" -class GrGLSLDitherEffect : public GrGLSLFragmentProcessor { -public: - GrGLSLDitherEffect() {} - void emitCode(EmitArgs& args) override { - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const GrDitherEffect& _outer = args.fFp.cast<GrDitherEffect>(); - (void)_outer; - auto rangeType = _outer.rangeType(); - (void)rangeType; - fragBuilder->codeAppendf( - "half value;\nhalf range;\n@switch (%d) {\n case 0:\n range = " - "0.0039215686274509803;\n break;\n case 1:\n range = " - "0.015873015873015872;\n break;\n default:\n range = " - "0.066666666666666666;\n break;\n}\n@if (sk_Caps.integerSupport) {\n " - "uint x = uint(sk_FragCoord.x);\n uint y = uint(sk_FragCoord.y);\n uint m = " - "(((((y & 1) << 5 | (x & 1) << 4) | (y & 2) << 2) | (x & 2) << 1) | (y & 4) >> 1) " - "| (x & 4) >> 2;\n value = float(float(half(m)) / 64.0) - 0.4", - _outer.rangeType()); - fragBuilder->codeAppendf( - "921875;\n} else {\n half4 modValues = half4(mod(sk_FragCoord.xyxy, " - "float4(half4(2.0, 2.0, 4.0, 4.0))));\n half4 stepValues = " - "half4(step(float4(modValues), float4(half4(1.0, 1.0, 2.0, 2.0))));\n value = " - "float(dot(stepValues, half4(0.5, 0.25, 0.125, 0.0625))) - 0.46875;\n}\n%s = " - "half4(clamp(float3(%s.xyz + value * range), 0.0, float(%s.w)), %s.w);\n", - args.fOutputColor, args.fInputColor ? args.fInputColor : "half4(1)", - args.fInputColor ? args.fInputColor : "half4(1)", - args.fInputColor ? args.fInputColor : "half4(1)"); - } - -private: - void onSetData(const GrGLSLProgramDataManager& pdman, - const GrFragmentProcessor& _proc) override {} -}; -GrGLSLFragmentProcessor* GrDitherEffect::onCreateGLSLInstance() const { - return new GrGLSLDitherEffect(); -} -void GrDitherEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const { - b->add32((int32_t)fRangeType); -} -bool GrDitherEffect::onIsEqual(const GrFragmentProcessor& other) const { - const GrDitherEffect& that = other.cast<GrDitherEffect>(); - (void)that; - if (fRangeType != that.fRangeType) return false; - return true; -} -GrDitherEffect::GrDitherEffect(const GrDitherEffect& src) - : INHERITED(kGrDitherEffect_ClassID, src.optimizationFlags()), fRangeType(src.fRangeType) {} -std::unique_ptr<GrFragmentProcessor> GrDitherEffect::clone() const { - return std::unique_ptr<GrFragmentProcessor>(new GrDitherEffect(*this)); -} -GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDitherEffect); -#if GR_TEST_UTILS -std::unique_ptr<GrFragmentProcessor> GrDitherEffect::TestCreate(GrProcessorTestData* testData) { - float range = testData->fRandom->nextRangeF(0.001f, 0.05f); - return std::unique_ptr<GrFragmentProcessor>(new GrDitherEffect(range)); -} -#endif diff --git a/src/gpu/effects/GrDitherEffect.fp b/src/gpu/effects/GrDitherEffect.fp deleted file mode 100644 index ed6c0e6b70..0000000000 --- a/src/gpu/effects/GrDitherEffect.fp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -// This controls the range of values added to color channels -layout(key) in int rangeType; - -@make { - static std::unique_ptr<GrFragmentProcessor> Make(GrPixelConfig dstConfig) { - int rangeType; - switch (dstConfig) { - case kGray_8_GrPixelConfig: - case kGray_8_as_Lum_GrPixelConfig: - case kGray_8_as_Red_GrPixelConfig: - case kRGBA_8888_GrPixelConfig: - case kRGB_888_GrPixelConfig: - case kBGRA_8888_GrPixelConfig: - rangeType = 0; - break; - case kRGB_565_GrPixelConfig: - rangeType = 1; - break; - case kRGBA_4444_GrPixelConfig: - rangeType = 2; - break; - case kUnknown_GrPixelConfig: - case kSRGBA_8888_GrPixelConfig: - case kSBGRA_8888_GrPixelConfig: - case kRGBA_1010102_GrPixelConfig: - case kAlpha_half_GrPixelConfig: - case kAlpha_half_as_Red_GrPixelConfig: - case kRGBA_float_GrPixelConfig: - case kRG_float_GrPixelConfig: - case kRGBA_half_GrPixelConfig: - case kAlpha_8_GrPixelConfig: - case kAlpha_8_as_Alpha_GrPixelConfig: - case kAlpha_8_as_Red_GrPixelConfig: - return nullptr; - } - return std::unique_ptr<GrFragmentProcessor>(new GrDitherEffect(rangeType)); - } -} - -void main() { - half value; - half range; - @switch (rangeType) { - case 0: - range = 1.0 / 255.0; - break; - case 1: - range = 1.0 / 63.0; - break; - default: - // Experimentally this looks better than the expected value of 1/15. - range = 1.0 / 15.0; - break; - } - @if (sk_Caps.integerSupport) { - // This ordered-dither code is lifted from the cpu backend. - uint x = uint(sk_FragCoord.x); - uint y = uint(sk_FragCoord.y); - uint m = (y & 1) << 5 | (x & 1) << 4 | - (y & 2) << 2 | (x & 2) << 1 | - (y & 4) >> 1 | (x & 4) >> 2; - value = half(m) * 1.0 / 64.0 - 63.0 / 128.0; - } else { - // Simulate the integer effect used above using step/mod. For speed, simulates a 4x4 - // dither pattern rather than an 8x8 one. - half4 modValues = mod(sk_FragCoord.xyxy, half4(2.0, 2.0, 4.0, 4.0)); - half4 stepValues = step(modValues, half4(1.0, 1.0, 2.0, 2.0)); - value = dot(stepValues, half4(8.0 / 16.0, 4.0 / 16.0, 2.0 / 16.0, 1.0 / 16.0)) - 15.0 / 32.0; - } - // For each color channel, add the random offset to the channel value and then clamp - // between 0 and alpha to keep the color premultiplied. - sk_OutColor = half4(clamp(sk_InColor.rgb + value * range, 0, sk_InColor.a), sk_InColor.a); -} - -@test(testData) { - float range = testData->fRandom->nextRangeF(0.001f, 0.05f); - return std::unique_ptr<GrFragmentProcessor>(new GrDitherEffect(range)); -} diff --git a/src/gpu/effects/GrDitherEffect.h b/src/gpu/effects/GrDitherEffect.h deleted file mode 100644 index 70adc45e6a..0000000000 --- a/src/gpu/effects/GrDitherEffect.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/************************************************************************************************** - *** This file was autogenerated from GrDitherEffect.fp; do not modify. - **************************************************************************************************/ -#ifndef GrDitherEffect_DEFINED -#define GrDitherEffect_DEFINED -#include "SkTypes.h" -#include "GrFragmentProcessor.h" -#include "GrCoordTransform.h" -class GrDitherEffect : public GrFragmentProcessor { -public: - int rangeType() const { return fRangeType; } - - static std::unique_ptr<GrFragmentProcessor> Make(GrPixelConfig dstConfig) { - int rangeType; - switch (dstConfig) { - case kGray_8_GrPixelConfig: - case kGray_8_as_Lum_GrPixelConfig: - case kGray_8_as_Red_GrPixelConfig: - case kRGBA_8888_GrPixelConfig: - case kRGB_888_GrPixelConfig: - case kBGRA_8888_GrPixelConfig: - rangeType = 0; - break; - case kRGB_565_GrPixelConfig: - rangeType = 1; - break; - case kRGBA_4444_GrPixelConfig: - rangeType = 2; - break; - case kUnknown_GrPixelConfig: - case kSRGBA_8888_GrPixelConfig: - case kSBGRA_8888_GrPixelConfig: - case kRGBA_1010102_GrPixelConfig: - case kAlpha_half_GrPixelConfig: - case kAlpha_half_as_Red_GrPixelConfig: - case kRGBA_float_GrPixelConfig: - case kRG_float_GrPixelConfig: - case kRGBA_half_GrPixelConfig: - case kAlpha_8_GrPixelConfig: - case kAlpha_8_as_Alpha_GrPixelConfig: - case kAlpha_8_as_Red_GrPixelConfig: - return nullptr; - } - return std::unique_ptr<GrFragmentProcessor>(new GrDitherEffect(rangeType)); - } - GrDitherEffect(const GrDitherEffect& src); - std::unique_ptr<GrFragmentProcessor> clone() const override; - const char* name() const override { return "DitherEffect"; } - -private: - GrDitherEffect(int rangeType) - : INHERITED(kGrDitherEffect_ClassID, kNone_OptimizationFlags), fRangeType(rangeType) {} - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; - bool onIsEqual(const GrFragmentProcessor&) const override; - GR_DECLARE_FRAGMENT_PROCESSOR_TEST - int fRangeType; - typedef GrFragmentProcessor INHERITED; -}; -#endif diff --git a/src/gpu/effects/GrRectBlurEffect.cpp b/src/gpu/effects/GrRectBlurEffect.cpp index 219fefa713..d423b786ce 100644 --- a/src/gpu/effects/GrRectBlurEffect.cpp +++ b/src/gpu/effects/GrRectBlurEffect.cpp @@ -46,13 +46,13 @@ public: fProfileSizeVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, kDefault_GrSLPrecision, "profileSize"); fragBuilder->codeAppendf( - "bool highPrecision = %s;\n@if (highPrecision) {\n float2 translatedPos = " - "sk_FragCoord.xy - %s.xy;\n float width = %s.z - %s.x;\n float height = %s.w " - "- %s.y;\n float2 smallDims = float2(width - float(%s), height - float(%s));\n " - " float center = 2.0 * floor(float(float(%s / 2.0) + 0.25)) - 1.0;\n float2 wh " - "= smallDims - float2(center, center);\n half hcoord = " - "half((abs(translatedPos.x - 0.5 * width) - 0.5 * wh.x) / float(%s));\n half " - "hlookup = texture(%s, float2(float(hcoord), 0.5)).%s.w", + "/* key */ bool highPrecision = %s;\n@if (highPrecision) {\n float2 " + "translatedPos = sk_FragCoord.xy - %s.xy;\n float width = %s.z - %s.x;\n " + "float height = %s.w - %s.y;\n float2 smallDims = float2(width - float(%s), " + "height - float(%s));\n float center = 2.0 * floor(float(float(%s / 2.0) + " + "0.25)) - 1.0;\n float2 wh = smallDims - float2(center, center);\n half " + "hcoord = half((abs(translatedPos.x - 0.5 * width) - 0.5 * wh.x) / float(%s));\n " + " half hlookup = texture(%s, float2(float(hcoord), ", (highPrecision ? "true" : "false"), args.fUniformHandler->getUniformCStr(fRectVar), args.fUniformHandler->getUniformCStr(fRectVar), args.fUniformHandler->getUniformCStr(fRectVar), @@ -62,16 +62,16 @@ public: args.fUniformHandler->getUniformCStr(fProfileSizeVar), args.fUniformHandler->getUniformCStr(fProfileSizeVar), args.fUniformHandler->getUniformCStr(fProfileSizeVar), - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(), - fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str()); + fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str()); fragBuilder->codeAppendf( - ";\n half vcoord = half((abs(translatedPos.y - 0.5 * height) - 0.5 * wh.y) / " - "float(%s));\n half vlookup = texture(%s, float2(float(vcoord), 0.5)).%s.w;\n " - " %s = (%s * hlookup) * vlookup;\n} else {\n half2 translatedPos = " - "half2(sk_FragCoord.xy - %s.xy);\n half width = half(%s.z - %s.x);\n half " - "height = half(%s.w - %s.y);\n half2 smallDims = half2(width - %s, height - " - "%s);\n half center = half(2.0 * floor(float(float(%s / 2.0) + 0.25)) - 1.0);\n " - " half2 wh = smallDims - half2(float2(floa", + "0.5)).%s.w;\n half vcoord = half((abs(translatedPos.y - 0.5 * height) - 0.5 * " + "wh.y) / float(%s));\n half vlookup = texture(%s, float2(float(vcoord), " + "0.5)).%s.w;\n %s = (%s * hlookup) * vlookup;\n} else {\n half2 " + "translatedPos = half2(sk_FragCoord.xy - %s.xy);\n half width = half(%s.z - " + "%s.x);\n half height = half(%s.w - %s.y);\n half2 smallDims = half2(width - " + "%s, height - %s);\n half center = half(2.0 * floor(float(float(%s / 2.0) + " + "0.25)) - 1.0);\n half2 wh = smallDims - half2(f", + fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(), args.fUniformHandler->getUniformCStr(fProfileSizeVar), fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(), fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str(), @@ -85,7 +85,7 @@ public: args.fUniformHandler->getUniformCStr(fProfileSizeVar), args.fUniformHandler->getUniformCStr(fProfileSizeVar)); fragBuilder->codeAppendf( - "t(center), float(center)));\n half hcoord = " + "loat2(float(center), float(center)));\n half hcoord = " "half((abs(float(float(translatedPos.x) - 0.5 * float(width))) - 0.5 * " "float(wh.x)) / float(%s));\n half hlookup = texture(%s, float2(float(hcoord), " "0.5)).%s.w;\n half vcoord = half((abs(float(float(translatedPos.y) - 0.5 * " diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp new file mode 100644 index 0000000000..bc84c833d7 --- /dev/null +++ b/src/gpu/effects/GrSkSLFP.cpp @@ -0,0 +1,268 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrSkSLFP.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "glsl/GrGLSLProgramBuilder.h" +#include "GrContext.h" +#include "GrContextPriv.h" +#include "GrTexture.h" +#include "SkSLUtil.h" + +GrSkSLFPFactory::GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl) + : fName(name) { + SkSL::Program::Settings settings; + settings.fCaps = shaderCaps; + fBaseProgram = fCompiler.convertProgram(SkSL::Program::kPipelineStage_Kind, + SkSL::String(sksl), + settings); + if (fCompiler.errorCount()) { + SkDebugf("%s\n", fCompiler.errorText().c_str()); + } + SkASSERT(fBaseProgram); + SkASSERT(!fCompiler.errorCount()); + for (const auto& e : *fBaseProgram) { + if (e.fKind == SkSL::ProgramElement::kVar_Kind) { + SkSL::VarDeclarations& v = (SkSL::VarDeclarations&) e; + for (const auto& varStatement : v.fVars) { + const SkSL::Variable& var = *((SkSL::VarDeclaration&) *varStatement).fVar; + if (var.fModifiers.fFlags & SkSL::Modifiers::kIn_Flag) { + fInputVars.push_back(&var); + } + if (var.fModifiers.fLayout.fKey) { + fKeyVars.push_back(&var); + } + } + } + } +} + +const SkSL::Program* GrSkSLFPFactory::getSpecialization(const SkSL::String& key, const void* inputs, + size_t inputSize) { + const auto& found = fSpecializations.find(key); + if (found != fSpecializations.end()) { + return found->second.get(); + } + + std::unordered_map<SkSL::String, SkSL::Program::Settings::Value> inputMap; + size_t offset = 0; + for (const auto& v : fInputVars) { + SkSL::String name(v->fName); + if (&v->fType == fCompiler.context().fInt_Type.get()) { + offset = SkAlign4(offset); + int32_t v = *(int32_t*) (((uint8_t*) inputs) + offset); + inputMap.insert(std::make_pair(name, SkSL::Program::Settings::Value(v))); + offset += sizeof(int32_t); + } + } + SkASSERT(offset == inputSize); + + std::unique_ptr<SkSL::Program> specialized = fCompiler.specialize(*fBaseProgram, inputMap); + SkAssertResult(fCompiler.optimize(*specialized)); + const SkSL::Program* result = specialized.get(); + fSpecializations.insert(std::make_pair(key, std::move(specialized))); + return result; +} + +class GrGLSLSkSLFP : public GrGLSLFragmentProcessor { +public: + GrGLSLSkSLFP(SkSL::String glsl, std::vector<SkSL::Compiler::FormatArg> formatArgs) + : fGLSL(glsl) + , fFormatArgs(formatArgs) {} + + void emitCode(EmitArgs& args) override { + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + int substringStartIndex = 0; + int formatArgIndex = 0; + for (size_t i = 0; i < fGLSL.length(); ++i) { + char c = fGLSL[i]; + if (c == '%') { + fragBuilder->codeAppend(fGLSL.c_str() + substringStartIndex, + i - substringStartIndex); + ++i; + c = fGLSL[i]; + switch (c) { + case 's': + switch (fFormatArgs[formatArgIndex++]) { + case SkSL::Compiler::FormatArg::kInput: + fragBuilder->codeAppend(args.fInputColor ? args.fInputColor + : "half4(1)"); + break; + case SkSL::Compiler::FormatArg::kOutput: + fragBuilder->codeAppend(args.fOutputColor); + break; + } + break; + default: + fragBuilder->codeAppendf("%c", c); + } + substringStartIndex = i + 1; + } + } + fragBuilder->codeAppend(fGLSL.c_str() + substringStartIndex, + fGLSL.length() - substringStartIndex); + } + + // nearly-finished GLSL; still contains printf-style "%s" format tokens + const SkSL::String fGLSL; + std::vector<SkSL::Compiler::FormatArg> fFormatArgs; +}; + +std::unique_ptr<GrFragmentProcessor> GrSkSLFP::Make(GrContext* context, int index, const char* name, + const char* sksl, const void* inputs, + size_t inputSize) { + return std::unique_ptr<GrFragmentProcessor>(new GrSkSLFP( + context->contextPriv().getFPFactoryCache(), + context->contextPriv().caps()->shaderCaps(), + index, name, sksl, inputs, inputSize)); +} + + +GrSkSLFP::GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache, const GrShaderCaps* shaderCaps, + int index, const char* name, const char* sksl, const void* inputs, + size_t inputSize) + : INHERITED(kGrSkSLFP_ClassID, kNone_OptimizationFlags) + , fFactoryCache(factoryCache) + , fShaderCaps(sk_ref_sp(shaderCaps)) + , fIndex(index) + , fName(name) + , fSkSL(sksl) + , fInputs(new int8_t[inputSize]) + , fInputSize(inputSize) { + memcpy(fInputs.get(), inputs, inputSize); +} + +GrSkSLFP::GrSkSLFP(const GrSkSLFP& other) + : INHERITED(kGrSkSLFP_ClassID, kNone_OptimizationFlags) + , fFactoryCache(other.fFactoryCache) + , fShaderCaps(other.fShaderCaps) + , fFactory(other.fFactory) + , fIndex(other.fIndex) + , fName(other.fName) + , fSkSL(other.fSkSL) + , fInputs(new int8_t[other.fInputSize]) + , fInputSize(other.fInputSize) { + memcpy(fInputs.get(), other.fInputs.get(), fInputSize); +} + +const char* GrSkSLFP::name() const { + return fName; +} + +void GrSkSLFP::createFactory() const { + if (!fFactory) { + fFactory = fFactoryCache->get(fIndex); + if (!fFactory) { + fFactory = sk_sp<GrSkSLFPFactory>(new GrSkSLFPFactory(fName, fShaderCaps.get(), fSkSL)); + fFactoryCache->set(fIndex, fFactory); + } + } +} + +GrGLSLFragmentProcessor* GrSkSLFP::onCreateGLSLInstance() const { + this->createFactory(); + const SkSL::Program* specialized = fFactory->getSpecialization(fKey, fInputs.get(), fInputSize); + SkSL::String glsl; + std::vector<SkSL::Compiler::FormatArg> formatArgs; + if (!fFactory->fCompiler.toPipelineStage(*specialized, &glsl, &formatArgs)) { + printf("%s\n", fFactory->fCompiler.errorText().c_str()); + abort(); + } + return new GrGLSLSkSLFP(glsl, formatArgs); +} + +void GrSkSLFP::onGetGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const { + this->createFactory(); + size_t offset = 0; + char* inputs = (char*) fInputs.get(); + for (const auto& v : fFactory->fInputVars) { + if (&v->fType == fFactory->fCompiler.context().fInt_Type.get()) { + offset = SkAlign4(offset); + if (v->fModifiers.fLayout.fKey) { + fKey += inputs[offset + 0]; + fKey += inputs[offset + 1]; + fKey += inputs[offset + 2]; + fKey += inputs[offset + 3]; + b->add32(*(int32_t*) (inputs + offset)); + } + offset += sizeof(int32_t); + } + else { + // unsupported input var type + SkASSERT(false); + } + } + SkASSERT(offset == fInputSize); +} + +bool GrSkSLFP::onIsEqual(const GrFragmentProcessor& other) const { + const GrSkSLFP& sk = other.cast<GrSkSLFP>(); + SkASSERT(fIndex != sk.fIndex || fInputSize == sk.fInputSize); + return fIndex == sk.fIndex && + !memcmp(fInputs.get(), sk.fInputs.get(), fInputSize); +} + +std::unique_ptr<GrFragmentProcessor> GrSkSLFP::clone() const { + return std::unique_ptr<GrFragmentProcessor>(new GrSkSLFP(*this)); +} + +// We have to do a bit of manual refcounting in the cache methods below. Ideally, we could just +// define fFactories to contain sk_sp<GrSkSLFPFactory> rather than GrSkSLFPFactory*, but that would +// require GrContext to include GrSkSLFP, which creates much bigger headaches than a few manual +// refcounts. + +sk_sp<GrSkSLFPFactory> GrSkSLFPFactoryCache::get(int index) { + if (index >= (int) fFactories.size()) { + return nullptr; + } + GrSkSLFPFactory* result = fFactories[index]; + result->ref(); + return sk_sp<GrSkSLFPFactory>(result); +} + +void GrSkSLFPFactoryCache::set(int index, sk_sp<GrSkSLFPFactory> factory) { + while (index >= (int) fFactories.size()) { + fFactories.emplace_back(); + } + factory->ref(); + SkASSERT(!fFactories[index]); + fFactories[index] = factory.get(); +} + +GrSkSLFPFactoryCache::~GrSkSLFPFactoryCache() { + for (GrSkSLFPFactory* factory : fFactories) { + if (factory) { + factory->unref(); + } + } +} + +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSkSLFP); + +#if GR_TEST_UTILS + +#include "SkGr.h" + +using Value = SkSL::Program::Settings::Value; + +std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d) { + int type = d->fRandom->nextULessThan(1); + switch (type) { + case 0: { + static int ditherIndex = NewIndex(); + int rangeType = d->fRandom->nextULessThan(3); + return GrSkSLFP::Make(d->context(), ditherIndex, "Dither", SKSL_DITHER_SRC, &rangeType, + sizeof(rangeType)); + } + } + SK_ABORT("unreachable"); + return nullptr; +} + +#endif diff --git a/src/gpu/effects/GrSkSLFP.h b/src/gpu/effects/GrSkSLFP.h new file mode 100644 index 0000000000..428e0892e0 --- /dev/null +++ b/src/gpu/effects/GrSkSLFP.h @@ -0,0 +1,147 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSkSLFP_DEFINED +#define GrSkSLFP_DEFINED + +#include "GrCaps.h" +#include "GrFragmentProcessor.h" +#include "GrCoordTransform.h" +#include "GrShaderCaps.h" +#include "SkSLCompiler.h" +#include "SkSLPipelineStageCodeGenerator.h" +#include "SkRefCnt.h" +#include "../private/GrSkSLFPFactoryCache.h" + +class GrContext; +class GrSkSLFPFactory; + +class GrSkSLFP : public GrFragmentProcessor { +public: + /** + * Returns a new unique identifier. Each different SkSL fragment processor should call + * NewIndex once, statically, and use this index for all calls to Make. + */ + static int NewIndex() { + static int index = 0; + return sk_atomic_inc(&index); + } + + /** + * Creates a new fragment processor from an SkSL source string and a struct of inputs to the + * program. The input struct's type is derived from the 'in' variables in the SkSL source, so + * e.g. the shader: + * + * in bool dither; + * in float x; + * in float y; + * .... + * + * would expect a pointer to a struct set up like: + * + * struct { + * bool dither; + * float x; + * float y; + * }; + * + * As turning SkSL into GLSL / SPIR-V / etc. is fairly expensive, and the output may differ + * based on the inputs, internally the process is divided into two steps: we first parse and + * semantically analyze the SkSL into an internal representation, and then "specialize" this + * internal representation based on the inputs. The unspecialized internal representation of + * the program is cached, so further specializations of the same code are much faster than the + * first call. + * + * This caching is based on the 'index' parameter, which should be derived by statically calling + * 'NewIndex()'. Each given SkSL string should have a single, statically defined index + * associated with it. + */ + static std::unique_ptr<GrFragmentProcessor> Make( + GrContext* context, + int index, + const char* name, + const char* sksl, + const void* inputs, + size_t inputSize); + + const char* name() const override; + + std::unique_ptr<GrFragmentProcessor> clone() const override; + +private: + GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache, const GrShaderCaps* shaderCaps, int fIndex, + const char* name, const char* sksl, const void* inputs, size_t inputSize); + + GrSkSLFP(const GrSkSLFP& other); + + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; + + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; + + bool onIsEqual(const GrFragmentProcessor&) const override; + + void createFactory() const; + + sk_sp<GrSkSLFPFactoryCache> fFactoryCache; + + const sk_sp<GrShaderCaps> fShaderCaps; + + mutable sk_sp<GrSkSLFPFactory> fFactory; + + int fIndex; + + const char* fName; + + const char* fSkSL; + + const std::unique_ptr<int8_t[]> fInputs; + + size_t fInputSize; + + mutable SkSL::String fKey; + + GR_DECLARE_FRAGMENT_PROCESSOR_TEST + + typedef GrFragmentProcessor INHERITED; + + friend class GrSkSLFPFactory; +}; + +/** + * Produces GrFragmentProcessors from SkSL code. As the shader code produced from the SkSL depends + * upon the inputs to the SkSL (static if's, etc.) we first create a factory for a given SkSL + * string, then use that to create the actual GrFragmentProcessor. + */ +class GrSkSLFPFactory : public SkNVRefCnt<GrSkSLFPFactory> { +public: + /** + * Constructs a GrSkSLFPFactory for a given SkSL source string. Creating a factory will + * preprocess the SkSL and determine which of its inputs are declared "key" (meaning they cause + * the produced shaders to differ), so it is important to reuse the same factory instance for + * the same shader in order to avoid repeatedly re-parsing the SkSL. + */ + GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl); + + const SkSL::Program* getSpecialization(const SkSL::String& key, const void* inputs, + size_t inputSize); + + const char* fName; + + SkSL::Compiler fCompiler; + + std::shared_ptr<SkSL::Program> fBaseProgram; + + std::vector<const SkSL::Variable*> fInputVars; + + std::vector<const SkSL::Variable*> fKeyVars; + + std::unordered_map<SkSL::String, std::unique_ptr<const SkSL::Program>> fSpecializations; + + friend class GrSkSLFP; +}; + +#endif |