1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2019 Google LLC. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "gm/gm.h" 9cb93a386Sopenharmony_ci#include "include/core/SkFont.h" 10cb93a386Sopenharmony_ci#include "include/effects/SkRuntimeEffect.h" 11cb93a386Sopenharmony_ci#include "src/core/SkCanvasPriv.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrPaint.h" 14cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 15cb93a386Sopenharmony_ci#include "src/gpu/effects/GrMatrixEffect.h" 16cb93a386Sopenharmony_ci#include "src/gpu/effects/GrTextureEffect.h" 17cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 18cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 19cb93a386Sopenharmony_ci#include "tools/ToolUtils.h" 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_cinamespace { 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci// Samples child with a uniform matrix (functionally identical to GrMatrixEffect) 24cb93a386Sopenharmony_ci// Scales along Y 25cb93a386Sopenharmony_ciclass UniformMatrixEffect : public GrFragmentProcessor { 26cb93a386Sopenharmony_cipublic: 27cb93a386Sopenharmony_ci inline static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 4; 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci UniformMatrixEffect(std::unique_ptr<GrFragmentProcessor> child) 30cb93a386Sopenharmony_ci : GrFragmentProcessor(CLASS_ID, kNone_OptimizationFlags) { 31cb93a386Sopenharmony_ci this->registerChild(std::move(child), 32cb93a386Sopenharmony_ci SkSL::SampleUsage::UniformMatrix(/*hasPerspective=*/false)); 33cb93a386Sopenharmony_ci } 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci const char* name() const override { return "UniformMatrixEffect"; } 36cb93a386Sopenharmony_ci void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} 37cb93a386Sopenharmony_ci bool onIsEqual(const GrFragmentProcessor& that) const override { return this == &that; } 38cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> clone() const override { return nullptr; } 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ci std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override { 41cb93a386Sopenharmony_ci class Impl : public ProgramImpl { 42cb93a386Sopenharmony_ci public: 43cb93a386Sopenharmony_ci void emitCode(EmitArgs& args) override { 44cb93a386Sopenharmony_ci fMatrixVar = 45cb93a386Sopenharmony_ci args.fUniformHandler->addUniform(&args.fFp, 46cb93a386Sopenharmony_ci kFragment_GrShaderFlag, 47cb93a386Sopenharmony_ci kFloat3x3_GrSLType, 48cb93a386Sopenharmony_ci SkSL::SampleUsage::MatrixUniformName()); 49cb93a386Sopenharmony_ci SkString sample = this->invokeChildWithMatrix(0, args); 50cb93a386Sopenharmony_ci args.fFragBuilder->codeAppendf("return %s;\n", sample.c_str()); 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci private: 54cb93a386Sopenharmony_ci void onSetData(const GrGLSLProgramDataManager& pdman, 55cb93a386Sopenharmony_ci const GrFragmentProcessor& proc) override { 56cb93a386Sopenharmony_ci pdman.setSkMatrix(fMatrixVar, SkMatrix::Scale(1, 0.5f)); 57cb93a386Sopenharmony_ci } 58cb93a386Sopenharmony_ci UniformHandle fMatrixVar; 59cb93a386Sopenharmony_ci }; 60cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 61cb93a386Sopenharmony_ci } 62cb93a386Sopenharmony_ci}; 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci// Samples child with explicit coords 65cb93a386Sopenharmony_ci// Translates along Y 66cb93a386Sopenharmony_ciclass ExplicitCoordEffect : public GrFragmentProcessor { 67cb93a386Sopenharmony_cipublic: 68cb93a386Sopenharmony_ci inline static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 6; 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci ExplicitCoordEffect(std::unique_ptr<GrFragmentProcessor> child) 71cb93a386Sopenharmony_ci : GrFragmentProcessor(CLASS_ID, kNone_OptimizationFlags) { 72cb93a386Sopenharmony_ci this->registerChild(std::move(child), SkSL::SampleUsage::Explicit()); 73cb93a386Sopenharmony_ci this->setUsesSampleCoordsDirectly(); 74cb93a386Sopenharmony_ci } 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci const char* name() const override { return "ExplicitCoordEffect"; } 77cb93a386Sopenharmony_ci void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} 78cb93a386Sopenharmony_ci bool onIsEqual(const GrFragmentProcessor& that) const override { return this == &that; } 79cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> clone() const override { return nullptr; } 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ci std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override { 82cb93a386Sopenharmony_ci class Impl : public ProgramImpl { 83cb93a386Sopenharmony_ci public: 84cb93a386Sopenharmony_ci void emitCode(EmitArgs& args) override { 85cb93a386Sopenharmony_ci args.fFragBuilder->codeAppendf("float2 coord = %s + float2(0, 8);", 86cb93a386Sopenharmony_ci args.fSampleCoord); 87cb93a386Sopenharmony_ci SkString sample = this->invokeChild(0, args, "coord"); 88cb93a386Sopenharmony_ci args.fFragBuilder->codeAppendf("return %s;\n", sample.c_str()); 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci }; 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci}; 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci// Generates test pattern 97cb93a386Sopenharmony_ciclass TestPatternEffect : public GrFragmentProcessor { 98cb93a386Sopenharmony_cipublic: 99cb93a386Sopenharmony_ci inline static constexpr GrProcessor::ClassID CLASS_ID = (GrProcessor::ClassID) 7; 100cb93a386Sopenharmony_ci 101cb93a386Sopenharmony_ci TestPatternEffect() : GrFragmentProcessor(CLASS_ID, kNone_OptimizationFlags) { 102cb93a386Sopenharmony_ci this->setUsesSampleCoordsDirectly(); 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci const char* name() const override { return "TestPatternEffect"; } 106cb93a386Sopenharmony_ci void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} 107cb93a386Sopenharmony_ci bool onIsEqual(const GrFragmentProcessor& that) const override { return this == &that; } 108cb93a386Sopenharmony_ci std::unique_ptr<GrFragmentProcessor> clone() const override { return nullptr; } 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override { 111cb93a386Sopenharmony_ci class Impl : public ProgramImpl { 112cb93a386Sopenharmony_ci public: 113cb93a386Sopenharmony_ci void emitCode(EmitArgs& args) override { 114cb93a386Sopenharmony_ci auto fb = args.fFragBuilder; 115cb93a386Sopenharmony_ci fb->codeAppendf("float2 coord = %s / 64.0;", args.fSampleCoord); 116cb93a386Sopenharmony_ci fb->codeAppendf("coord = floor(coord * 4) / 3;"); 117cb93a386Sopenharmony_ci fb->codeAppendf("return half2(coord).rg01;\n"); 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci }; 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci}; 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ciSkBitmap make_test_bitmap() { 126cb93a386Sopenharmony_ci SkBitmap bitmap; 127cb93a386Sopenharmony_ci bitmap.allocN32Pixels(64, 64); 128cb93a386Sopenharmony_ci SkCanvas canvas(bitmap); 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci SkFont font(ToolUtils::create_portable_typeface()); 131cb93a386Sopenharmony_ci const char* alpha = "ABCDEFGHIJKLMNOP"; 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci for (int i = 0; i < 16; ++i) { 134cb93a386Sopenharmony_ci int tx = i % 4, 135cb93a386Sopenharmony_ci ty = i / 4; 136cb93a386Sopenharmony_ci int x = tx * 16, 137cb93a386Sopenharmony_ci y = ty * 16; 138cb93a386Sopenharmony_ci SkPaint paint; 139cb93a386Sopenharmony_ci paint.setColor4f({ tx / 3.0f, ty / 3.0f, 0.0f, 1.0f }); 140cb93a386Sopenharmony_ci canvas.drawRect(SkRect::MakeXYWH(x, y, 16, 16), paint); 141cb93a386Sopenharmony_ci paint.setColor4f({ (3-tx) / 3.0f, (3-ty)/3.0f, 1.0f, 1.0f }); 142cb93a386Sopenharmony_ci canvas.drawSimpleText(alpha + i, 1, SkTextEncoding::kUTF8, x + 3, y + 13, font, paint); 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci return bitmap; 146cb93a386Sopenharmony_ci} 147cb93a386Sopenharmony_ci 148cb93a386Sopenharmony_cienum EffectType { 149cb93a386Sopenharmony_ci kUniform, 150cb93a386Sopenharmony_ci kExplicit, 151cb93a386Sopenharmony_ci kDevice, 152cb93a386Sopenharmony_ci}; 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_cistatic std::unique_ptr<GrFragmentProcessor> wrap(std::unique_ptr<GrFragmentProcessor> fp, 155cb93a386Sopenharmony_ci EffectType effectType, 156cb93a386Sopenharmony_ci int drawX, int drawY) { 157cb93a386Sopenharmony_ci switch (effectType) { 158cb93a386Sopenharmony_ci case kUniform: 159cb93a386Sopenharmony_ci return std::make_unique<UniformMatrixEffect>(std::move(fp)); 160cb93a386Sopenharmony_ci case kExplicit: 161cb93a386Sopenharmony_ci return std::make_unique<ExplicitCoordEffect>(std::move(fp)); 162cb93a386Sopenharmony_ci case kDevice: 163cb93a386Sopenharmony_ci // Subtract out upper-left corner of draw so that device is effectively identity. 164cb93a386Sopenharmony_ci fp = GrMatrixEffect::Make(SkMatrix::Translate(-drawX, -drawY), std::move(fp)); 165cb93a386Sopenharmony_ci return GrFragmentProcessor::DeviceSpace(std::move(fp)); 166cb93a386Sopenharmony_ci } 167cb93a386Sopenharmony_ci SkUNREACHABLE; 168cb93a386Sopenharmony_ci} 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci} // namespace 171cb93a386Sopenharmony_ci 172cb93a386Sopenharmony_cinamespace skiagm { 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ciDEF_SIMPLE_GPU_GM_CAN_FAIL(fp_sample_chaining, rContext, canvas, errorMsg, 232, 306) { 175cb93a386Sopenharmony_ci auto sdc = SkCanvasPriv::TopDeviceSurfaceDrawContext(canvas); 176cb93a386Sopenharmony_ci if (!sdc) { 177cb93a386Sopenharmony_ci *errorMsg = GM::kErrorMsg_DrawSkippedGpuOnly; 178cb93a386Sopenharmony_ci return DrawResult::kSkip; 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci SkBitmap bmp = make_test_bitmap(); 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci int x = 10, y = 10; 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci auto nextCol = [&] { x += (64 + 10); }; 186cb93a386Sopenharmony_ci auto nextRow = [&] { x = 10; y += (64 + 10); }; 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci auto draw = [&](std::initializer_list<EffectType> effects) { 189cb93a386Sopenharmony_ci // Enable TestPatternEffect to get a fully procedural inner effect. It's not quite as nice 190cb93a386Sopenharmony_ci // visually (no text labels in each box), but it avoids the extra GrMatrixEffect. 191cb93a386Sopenharmony_ci // Switching it on actually triggers *more* shader compilation failures. 192cb93a386Sopenharmony_ci#if 0 193cb93a386Sopenharmony_ci auto fp = std::unique_ptr<GrFragmentProcessor>(new TestPatternEffect()); 194cb93a386Sopenharmony_ci#else 195cb93a386Sopenharmony_ci auto view = std::get<0>(GrMakeCachedBitmapProxyView(rContext, bmp, GrMipmapped::kNo)); 196cb93a386Sopenharmony_ci auto fp = GrTextureEffect::Make(std::move(view), bmp.alphaType()); 197cb93a386Sopenharmony_ci#endif 198cb93a386Sopenharmony_ci for (EffectType effectType : effects) { 199cb93a386Sopenharmony_ci fp = wrap(std::move(fp), effectType, x, y); 200cb93a386Sopenharmony_ci } 201cb93a386Sopenharmony_ci GrPaint paint; 202cb93a386Sopenharmony_ci paint.setColorFragmentProcessor(std::move(fp)); 203cb93a386Sopenharmony_ci sdc->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::Translate(x, y), 204cb93a386Sopenharmony_ci SkRect::MakeIWH(64, 64)); 205cb93a386Sopenharmony_ci nextCol(); 206cb93a386Sopenharmony_ci }; 207cb93a386Sopenharmony_ci 208cb93a386Sopenharmony_ci // Reminder, in every case, the chain is more complicated than it seems, because the 209cb93a386Sopenharmony_ci // GrTextureEffect is wrapped in a GrMatrixEffect, which is subject to the same bugs that 210cb93a386Sopenharmony_ci // we're testing (particularly the bug about owner/base in UniformMatrixEffect). 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_ci // First row: no transform, then each one independently applied 213cb93a386Sopenharmony_ci draw({}); // Identity (4 rows and columns) 214cb93a386Sopenharmony_ci draw({ kUniform }); // Scale Y axis by 2x (2 visible rows) 215cb93a386Sopenharmony_ci draw({ kExplicit }); // Translate up by 8px 216cb93a386Sopenharmony_ci nextRow(); 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ci // Second row: transform duplicated 219cb93a386Sopenharmony_ci draw({ kUniform, kUniform }); // Scale Y axis by 4x (1 visible row) 220cb93a386Sopenharmony_ci draw({ kExplicit, kExplicit }); // Translate up by 16px 221cb93a386Sopenharmony_ci nextRow(); 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_ci // Third row: Remember, these are applied inside out: 224cb93a386Sopenharmony_ci draw({ kUniform, kExplicit }); // Scale Y by 2x and translate up by 8px 225cb93a386Sopenharmony_ci draw({ kExplicit, kUniform }); // Scale Y by 2x and translate up by 16px 226cb93a386Sopenharmony_ci nextRow(); 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci // Fourth row: device space. 229cb93a386Sopenharmony_ci draw({ kDevice, kUniform }); // Same as identity (uniform applied *before* 230cb93a386Sopenharmony_ci // device so ignored). 231cb93a386Sopenharmony_ci draw({ kExplicit, kUniform, kDevice }); // Scale Y by 2x and translate up by 16px 232cb93a386Sopenharmony_ci draw({ kDevice, kExplicit, kUniform, kDevice }); // Identity, again. 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci return DrawResult::kOk; 235cb93a386Sopenharmony_ci} 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci} // namespace skiagm 238