/* * Copyright 2019 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "bench/Benchmark.h" #include "include/utils/SkRandom.h" #include "src/sksl/SkSLByteCode.h" #include "src/sksl/SkSLCompiler.h" #include "src/sksl/SkSLInterpreter.h" // Without this build flag, this bench isn't runnable. #if defined(SK_ENABLE_SKSL_INTERPRETER) // Benchmarks the interpreter with a function that has a color-filter style signature class SkSLInterpreterCFBench : public Benchmark { public: SkSLInterpreterCFBench(SkSL::String name, int pixels, const char* src) : fName(SkStringPrintf("sksl_interp_cf_%d_%s", pixels, name.c_str())) , fSrc(src) , fCount(pixels) {} protected: static constexpr int VecWidth = 16; const char* onGetName() override { return fName.c_str(); } bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; } void onDelayedSetup() override { SkSL::Compiler compiler; SkSL::Program::Settings settings; auto program = compiler.convertProgram(SkSL::Program::kGeneric_Kind, fSrc, settings); SkASSERT(compiler.errorCount() == 0); std::unique_ptr byteCode = compiler.toByteCode(*program); fMain = byteCode->getFunction("main"); fInterpreter.reset(new SkSL::Interpreter(std::move(byteCode))); SkASSERT(compiler.errorCount() == 0); SkRandom rnd; fPixels.resize(fCount * 4); for (float& c : fPixels) { c = rnd.nextF(); } } void onDraw(int loops, SkCanvas*) override { for (int i = 0; i < loops; i++) { float* args[] = { fPixels.data() + 0 * fCount, fPixels.data() + 1 * fCount, fPixels.data() + 2 * fCount, fPixels.data() + 3 * fCount, }; fInterpreter->runStriped(fMain, fCount, (float**) args); } } private: SkString fName; SkSL::String fSrc; std::unique_ptr> fInterpreter; const SkSL::ByteCodeFunction* fMain; int fCount; std::vector fPixels; typedef Benchmark INHERITED; }; /////////////////////////////////////////////////////////////////////////////// const char* kLumaToAlphaSrc = R"( void main(inout float4 color) { color.a = color.r*0.3 + color.g*0.6 + color.b*0.1; color.r = 0; color.g = 0; color.b = 0; } )"; const char* kHighContrastFilterSrc = R"( half ucontrast_Stage2; half hue2rgb_Stage2(half p, half q, half t) { if (t < 0) t += 1; if (t > 1) t -= 1; return (t < 1 / 6.) ? p + (q - p) * 6 * t : (t < 1 / 2.) ? q : (t < 2 / 3.) ? p + (q - p) * (2 / 3. - t) * 6 : p; } half max(half a, half b) { return a > b ? a : b; } half min(half a, half b) { return a < b ? a : b; } void main(inout half4 color) { ucontrast_Stage2 = 0.2; // HighContrastFilter half nonZeroAlpha = max(color.a, 0.0001); color = half4(color.rgb / nonZeroAlpha, nonZeroAlpha); color.rgb = color.rgb * color.rgb; half fmax = max(color.r, max(color.g, color.b)); half fmin = min(color.r, min(color.g, color.b)); half l = (fmax + fmin) / 2; half h; half s; if (fmax == fmin) { h = 0; s = 0; } else { half d = fmax - fmin; s = l > 0.5 ? d / (2 - fmax - fmin) : d / (fmax + fmin); if (color.r >= color.g && color.r >= color.b) { h = (color.g - color.b) / d + (color.g < color.b ? 6 : 0); } else if (color.g >= color.b) { h = (color.b - color.r) / d + 2; } else { h = (color.r - color.g) / d + 4; } } h /= 6; l = 1.0 - l; if (s == 0) { color = half4(l, l, l, 0); } else { half q = l < 0.5 ? l * (1 + s) : l + s - l * s; half p = 2 * l - q; color.r = hue2rgb_Stage2(p, q, h + 1 / 3.); color.g = hue2rgb_Stage2(p, q, h); color.b = hue2rgb_Stage2(p, q, h - 1 / 3.); } if (ucontrast_Stage2 != 0) { half m = (1 + ucontrast_Stage2) / (1 - ucontrast_Stage2); half off = (-0.5 * m + 0.5); color = m * color + off; } // color = saturate(color); color.rgb = sqrt(color.rgb); color.rgb *= color.a; } )"; DEF_BENCH(return new SkSLInterpreterCFBench("lumaToAlpha", 256, kLumaToAlphaSrc)); DEF_BENCH(return new SkSLInterpreterCFBench("hcf", 256, kHighContrastFilterSrc)); #endif // SK_ENABLE_SKSL_INTERPRETER