| /* |
| * Copyright 2021 Google LLC |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "gm/gm.h" |
| #include "include/core/SkCanvas.h" |
| #include "include/core/SkSize.h" |
| #include "include/core/SkString.h" |
| #include "include/core/SkSurface.h" |
| #include "include/effects/SkGradientShader.h" |
| #include "include/effects/SkRuntimeEffect.h" |
| #include "tools/Resources.h" |
| #include "tools/ToolUtils.h" |
| |
| class RuntimeEffectImage : public skiagm::GM { |
| public: |
| RuntimeEffectImage() = default; |
| |
| SkString onShortName() override { return SkString("runtime_effect_image"); } |
| |
| SkISize onISize() override { return {800, 200}; } |
| |
| protected: |
| void onOnceBeforeDraw() override { |
| SkString sksl(R"( |
| uniform shader child; |
| uniform half gAlphaType; // 0 is premul, non-zero unpremul. |
| |
| half4 main(float2 p) { |
| half r = fract(p.x/20); |
| half g = fract(p.y/20); |
| half b = fract((p.x + 5)/10); |
| half a = min(distance(p, vec2(50, 50))/50 + 0.3, 1); |
| half4 result = half4(r, g, b, a); |
| result *= child.eval(p); |
| if (gAlphaType == 0) { |
| result.rgb *= a; |
| } |
| return result; |
| } |
| )"); |
| auto [effect, error] = SkRuntimeEffect::MakeForShader(sksl); |
| if (!effect) { |
| SkDebugf("RuntimeShader error: %s\n", error.c_str()); |
| } |
| fEffect = std::move(effect); |
| } |
| |
| DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override { |
| GrRecordingContext* rc = canvas->recordingContext(); |
| SkRuntimeShaderBuilder builder(fEffect); |
| SkImageInfo info = SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType); |
| |
| SkSamplingOptions nn{SkFilterMode::kNearest}; |
| SkSamplingOptions mm{SkFilterMode::kLinear, SkMipmapMode::kNearest}; |
| auto whiteShader = SkShaders::Color(SK_ColorWHITE); |
| auto imageForShader = GetResourceAsImage("images/ducky.jpg"); |
| if (!imageForShader) { |
| *errorMsg = "Could not load image"; |
| return DrawResult::kFail; |
| } |
| auto imageShader = imageForShader->makeShader(SkTileMode::kRepeat, |
| SkTileMode::kRepeat, |
| SkSamplingOptions(SkFilterMode::kLinear), |
| SkMatrix::Scale(0.2f, 0.2f)); |
| |
| builder.uniform("gAlphaType") = 0.f; |
| builder.child("child") = whiteShader; |
| ToolUtils::draw_checkerboard(canvas, SK_ColorWHITE, SK_ColorLTGRAY, 50); |
| canvas->translate(5, 5); |
| SkPaint aaPaint; |
| aaPaint.setAntiAlias(true); |
| for (const auto& vm : {SkMatrix::Scale(1.5f, 1.5f), SkMatrix::Scale(0.3f, 0.3f)}) { |
| canvas->save(); |
| canvas->concat(vm); |
| |
| sk_sp<SkImage> image; |
| |
| // basic |
| image = builder.makeImage(rc, nullptr, info, false); |
| canvas->drawImage(image, 0, 0, nn, &aaPaint); |
| canvas->translate(105, 0); |
| |
| // local matrix |
| SkMatrix lm = SkMatrix::RotateDeg(45, {50, 50}); |
| lm.preTranslate(10, 10); |
| image = builder.makeImage(rc, &lm, info, false); |
| canvas->drawImage(image, 0, 0, nn, &aaPaint); |
| canvas->translate(105, 0); |
| |
| // unpremul |
| if (rc) { |
| // use a uniform to make the effect output be unpremul so it looks the same as the |
| // premul case when drawn to the canvas. |
| builder.uniform("gAlphaType") = 1.f; |
| image = builder.makeImage(rc, |
| nullptr, |
| info.makeAlphaType(kUnpremul_SkAlphaType), |
| false); |
| builder.uniform("gAlphaType") = 0.f; |
| canvas->drawImage(image, 0, 0, nn, &aaPaint); |
| canvas->translate(105, 0); |
| } else { |
| // CPU doesn't yet support making kUnpremul images. Just draw the basic one again. |
| image = builder.makeImage(nullptr, nullptr, info, false); |
| canvas->drawImage(image, 0, 0, nn, &aaPaint); |
| canvas->translate(105, 0); |
| } |
| |
| // color space |
| sk_sp<SkColorSpace> cs = SkColorSpace::MakeSRGB()->makeColorSpin(); |
| image = builder.makeImage(rc, nullptr, info.makeColorSpace(std::move(cs)), false); |
| canvas->drawImage(image, 0, 0, nn, &aaPaint); |
| canvas->translate(105, 0); |
| |
| // mipmapped and different child |
| builder.child("child") = imageShader; |
| image = builder.makeImage(rc, nullptr, info, true); |
| builder.child("child") = whiteShader; |
| canvas->drawImage(image, 0, 0, mm, &aaPaint); |
| canvas->translate(105, 0); |
| |
| canvas->restore(); |
| canvas->translate(0, 105*vm.getScaleY()); |
| } |
| return DrawResult::kOk; |
| } |
| |
| private: |
| sk_sp<SkRuntimeEffect> fEffect; |
| }; |
| DEF_GM(return new RuntimeEffectImage;) |