Runtime effect implementation of color cube filter

Bug: skia:10274
Change-Id: Ifb2ef8bf031e74d9d5c8183efe5aff4e6f3d2e7c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/292562
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2020-05-21 16:41:43 -04:00 committed by Skia Commit-Bot
parent afd4113bc3
commit 9c3eccd5d7
4 changed files with 86 additions and 0 deletions

View File

@ -237,3 +237,89 @@ class SpiralRT : public skiagm::GM {
}
};
DEF_GM(return new SpiralRT;)
class ColorCubeRT : public skiagm::GM {
sk_sp<SkImage> fMandrill, fMandrillSepia, fIdentityCube, fSepiaCube;
sk_sp<SkRuntimeEffect> fEffect;
void onOnceBeforeDraw() override {
fMandrill = GetResourceAsImage("images/mandrill_256.png");
fMandrillSepia = GetResourceAsImage("images/mandrill_sepia.png");
fIdentityCube = GetResourceAsImage("images/lut_identity.png");
fSepiaCube = GetResourceAsImage("images/lut_sepia.png");
const char code[] = R"(
in shader input;
in shader color_cube;
uniform float size;
uniform float size_minus_1;
void main(float2 xy, inout half4 color) {
float4 c = float4(unpremul(sample(input, xy)));
// Map to cube coords:
float3 cubeCoords = float3(c.rg * size_minus_1 + 0.5, c.b * size_minus_1);
// Compute slice coordinate
float2 coords1 = float2(floor(cubeCoords.b) * size + cubeCoords.r, cubeCoords.g);
float2 coords2 = float2( ceil(cubeCoords.b) * size + cubeCoords.r, cubeCoords.g);
// Two bilinear fetches, plus a manual lerp for the third axis:
color = mix(sample(color_cube, coords1), sample(color_cube, coords2),
half(fract(cubeCoords.b)));
// Premul again
color.rgb *= color.a;
}
)";
auto [effect, error] = SkRuntimeEffect::Make(SkString(code));
if (!effect) {
SkDebugf("runtime error %s\n", error.c_str());
}
fEffect = effect;
}
SkString onShortName() override { return SkString("color_cube_rt"); }
SkISize onISize() override { return {256 * 3, 256}; }
DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
if (canvas->getGrContext() == nullptr) {
// until SkSL can handle child processors on the raster backend
return DrawResult::kSkip;
}
// First we draw the unmodified image, and a copy that was sepia-toned in Photoshop:
canvas->drawImage(fMandrill, 0, 0);
canvas->drawImage(fMandrillSepia, 0, 256);
// LUT dimensions should be (kSize^2, kSize)
constexpr float kSize = 16.0f;
SkRuntimeShaderBuilder builder(fEffect);
builder.input("size") = kSize;
builder.input("size_minus_1") = kSize - 1;
builder.child("input") = fMandrill->makeShader();
// TODO: Move filter quality to the shader itself. We need to enforce at least kLow here
// so that we bilerp the color cube image.
SkPaint paint;
paint.setFilterQuality(kLow_SkFilterQuality);
// Now draw the image with an identity color cube - it should look like the original
builder.child("color_cube") = fIdentityCube->makeShader();
paint.setShader(builder.makeShader(nullptr, true));
canvas->translate(256, 0);
canvas->drawRect({ 0, 0, 256, 256 }, paint);
// ... and with a sepia-tone color cube. This should match the sepia-toned image.
builder.child("color_cube") = fSepiaCube->makeShader();
paint.setShader(builder.makeShader(nullptr, true));
canvas->translate(0, 256);
canvas->drawRect({ 0, 0, 256, 256 }, paint);
return DrawResult::kOk;
}
};
DEF_GM(return new ColorCubeRT;)

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB