skia2/gm/runtimeeffectimage.cpp
Brian Salomon 04aef10c64 Add SkRuntimeEffect::makeImage()
Allows creation of an image directly from a RTE. Caller provides the
effect input bindings, image info for the image, and optional local
matrix.

The info's alpha type and colorspace are tags for the output image. No
alpha type or color space conversions are applied to the output of RTE.

CPU does not yet support making kUnpremul images.

Bug: chromium:1151490

Change-Id: I69babc9dbbce4431d756cd7a3eef4753e727d6fe
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/357284
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Derek Sollenberger <djsollen@google.com>
Reviewed-by: Mike Reed <reed@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
2021-01-23 17:40:23 +00:00

136 lines
5.1 KiB
C++

/*
* 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 *= sample(child);
if (gAlphaType == 0) {
result.rgb *= a;
}
return result;
}
)");
auto [effect, error] = SkRuntimeEffect::Make(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;)