skia2/gm/ducky_yuv_blend.cpp
Brian Salomon c75bc031ef Clamp RGB outputs of GrYUVtoRGBEffect.
The matrices we're using can produce very slightly out of range color
channels. This gives surprising results when in shader blending is used
for color burn and color dodge. After this change we clamp the RGB
values to 0..1 before applying premul.

Adds a GM modeled on a blink layout test that shows the problem using
SkImageMakeFromYUVAPixmaps.


Bug: skia:9619


Change-Id: I446d39763a7f5a2f7c5f61d94d163927d851baa3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/253879
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
2019-11-11 20:04:15 +00:00

89 lines
3.3 KiB
C++

/*
* Copyright 2019 Google Inc.
*
* 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/SkPaint.h"
#include "include/core/SkYUVAIndex.h"
#include "include/core/SkYUVASizeInfo.h"
#include "src/core/SkCachedData.h"
#include "src/image/SkImage_Base.h"
#include "tools/Resources.h"
#include "tools/ToolUtils.h"
// Modeled on the layout test css3/blending/background-blend-mode-image-image.html to reproduce
// skbug.com/9619
DEF_SIMPLE_GM_CAN_FAIL(ducky_yuv_blend, canvas, errorMsg, 560, 1130) {
sk_sp<SkImage> duckyBG = GetResourceAsImage("ducky.png");
sk_sp<SkImage> duckyFG[2] = {GetResourceAsImage("ducky.jpg"), nullptr};
if (!duckyFG[0] || !duckyBG) {
*errorMsg = "Image(s) failed to load.";
return skiagm::DrawResult::kFail;
}
// If we're on the GPU we do a second round of draws where the source image is YUV planes.
// Otherwise we just draw the original again,
if (auto* context = canvas->getGrContext()) {
SkYUVASizeInfo info;
SkYUVAIndex indices[4];
SkYUVColorSpace yuvColorSpace;
const void* planes[4];
auto data = as_IB(duckyFG[0])->getPlanes(&info, indices, &yuvColorSpace, planes);
SkPixmap pixmaps[4];
for (int i = 0; i < 4; ++i) {
if (indices[i].fIndex >= 0) {
pixmaps[i].reset(
SkImageInfo::MakeA8(info.fSizes[i]), planes[i], info.fWidthBytes[i]);
}
}
duckyFG[1] = SkImage::MakeFromYUVAPixmaps(context,
yuvColorSpace,
pixmaps,
indices,
duckyFG[0]->dimensions(),
kTopLeft_GrSurfaceOrigin,
true);
} else {
duckyFG[1] = duckyFG[0];
}
static constexpr int kNumPerRow = 4;
static constexpr int kPad = 10;
static constexpr auto kDstRect = SkRect::MakeWH(130, 130);
int rowCnt = 0;
canvas->translate(kPad, kPad);
canvas->save();
auto newRow = [&] {
canvas->restore();
canvas->translate(0, kDstRect.height() + kPad);
canvas->save();
rowCnt = 0;
};
ToolUtils::draw_checkerboard(
canvas, SK_ColorDKGRAY, SK_ColorLTGRAY, (kDstRect.height() + kPad)/5);
for (auto& fg : duckyFG) {
for (int bm = static_cast<int>(SkBlendMode::kLastCoeffMode) + 1;
bm < static_cast<int>(SkBlendMode::kLastMode);
++bm) {
auto mode = static_cast<SkBlendMode>(bm);
SkPaint paint;
paint.setFilterQuality(kMedium_SkFilterQuality);
canvas->drawImageRect(duckyBG, kDstRect, &paint);
paint.setBlendMode(mode);
canvas->drawImageRect(fg, kDstRect, &paint);
canvas->translate(kDstRect.width() + kPad, 0);
if (++rowCnt == kNumPerRow) {
newRow();
}
}
// Force a new row between the two foreground images
newRow();
}
canvas->restore();
return skiagm::DrawResult::kOk;
}