skia::DrawGainmapImage: Fix cubic sampling
When cubic sampling is used, the gainmap shader fails because it uses SkImage::makeRawShader, which does not support cubic sampling. Fall back to linear sampling in that case. Bug: 374783345 Change-Id: I55caf3688d8338798c1358c19e08b147794abf91 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5952964 Reviewed-by: Michael Ludwig <michaelludwig@google.com> Commit-Queue: ccameron chromium <ccameron@chromium.org> Cr-Commit-Position: refs/heads/main@{#1373772}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
f53c507d9a
commit
86596c43e6
@ -724,8 +724,11 @@ TEST_F(OopPixelTest, DrawGainmapImage) {
|
||||
|
||||
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
|
||||
display_item_list->StartPaint();
|
||||
SkSamplingOptions sampling(
|
||||
PaintFlags::FilterQualityToSkSamplingOptions(kDefaultFilterQuality));
|
||||
|
||||
// Use cubic sampling, to ensure that it does not cause corruption or crashes.
|
||||
// https://crbug.com/374783345
|
||||
SkSamplingOptions sampling =
|
||||
SkSamplingOptions(SkCubicResampler::CatmullRom());
|
||||
display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, sampling,
|
||||
nullptr);
|
||||
display_item_list->EndPaintOfUnpaired(kRect);
|
||||
@ -769,6 +772,93 @@ TEST_F(OopPixelTest, DrawGainmapImage) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(OopPixelTest, DrawGainmapImageCubic) {
|
||||
constexpr uint32_t kSrcSize = 2;
|
||||
constexpr uint32_t kDstSize = 4;
|
||||
|
||||
// The gainmap is fully applied at headroom 2, and has a maximum scale of 4.
|
||||
const float kRatioMax = 4.f;
|
||||
SkGainmapInfo gainmap_info = {
|
||||
{1.f, 1.f, 1.f, 1.f},
|
||||
{kRatioMax, kRatioMax, kRatioMax, 1.f},
|
||||
{1.f, 1.f, 1.f, 1.f},
|
||||
{0.f, 0.f, 0.f, 1.f},
|
||||
{0.f, 0.f, 0.f, 1.f},
|
||||
1.f,
|
||||
kRatioMax,
|
||||
SkGainmapInfo::BaseImageType::kSDR,
|
||||
SkGainmapInfo::Type::kDefault,
|
||||
nullptr,
|
||||
};
|
||||
|
||||
auto info = SkImageInfo::MakeN32Premul(kSrcSize, kSrcSize,
|
||||
SkColorSpace::MakeSRGBLinear());
|
||||
sk_sp<FakePaintImageGenerator> generators[2];
|
||||
uint8_t pixel_values[2][2] = {
|
||||
{100, 20},
|
||||
{static_cast<uint8_t>(
|
||||
std::round(255.f * std::log(2.f) / std::log(kRatioMax))),
|
||||
static_cast<uint8_t>(
|
||||
std::round(255.f * std::log(3.f) / std::log(kRatioMax)))}};
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
generators[i] = sk_make_sp<FakePaintImageGenerator>(info);
|
||||
SkPixmap pm = generators[i]->GetPixmap();
|
||||
for (size_t x = 0; x < kSrcSize; ++x) {
|
||||
for (size_t y = 0; y < kSrcSize; ++y) {
|
||||
uint32_t* pixel = pm.writable_addr32(x, y);
|
||||
uint8_t v = pixel_values[i][x];
|
||||
*pixel = SkColorSetARGB(255, v, v, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw with cubic filtering. This will get demoted to linear filtering.
|
||||
static int counter = 0;
|
||||
const PaintImage::Id kSomeId = 32 + counter++;
|
||||
auto paint_image =
|
||||
PaintImageBuilder::WithDefault()
|
||||
.set_id(kSomeId)
|
||||
.set_paint_image_generator(generators[0])
|
||||
.set_gainmap_paint_image_generator(generators[1], gainmap_info)
|
||||
.TakePaintImage();
|
||||
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
|
||||
{
|
||||
display_item_list->StartPaint();
|
||||
display_item_list->push<DrawImageRectOp>(
|
||||
paint_image, SkRect::MakeWH(kSrcSize, kSrcSize),
|
||||
SkRect::MakeWH(kDstSize, kDstSize),
|
||||
SkSamplingOptions(SkCubicResampler::CatmullRom()), nullptr,
|
||||
SkCanvas::kStrict_SrcRectConstraint);
|
||||
display_item_list->EndPaintOfUnpaired(gfx::Rect(0, 0, kDstSize, kDstSize));
|
||||
display_item_list->Finalize();
|
||||
}
|
||||
RasterOptions options(gfx::Size(kDstSize, kDstSize));
|
||||
{
|
||||
auto dest_color_space = SkColorSpace::MakeSRGBLinear();
|
||||
options.target_color_params.color_space =
|
||||
gfx::ColorSpace(*dest_color_space);
|
||||
options.target_color_params.hdr_max_luminance_relative = kRatioMax;
|
||||
}
|
||||
auto result = Raster(display_item_list, options);
|
||||
|
||||
// Check pixel values against manually computed expected values.
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
// Compute the linearly interpolated base and gainmap pixel values.
|
||||
float base_value =
|
||||
((3.f - i) * pixel_values[0][0] + i * pixel_values[0][1]) /
|
||||
(255.f * 3.f);
|
||||
float gain_value =
|
||||
((3.f - i) * pixel_values[1][0] + i * pixel_values[1][1]) /
|
||||
(255.f * 3.f);
|
||||
|
||||
// Compute the expected value using the interpolated values.
|
||||
float expected = base_value * std::exp(gain_value * std::log(kRatioMax));
|
||||
float actual = result.getColor4f(i, 0).fR;
|
||||
float kEpsilon = 16.f / 255.f;
|
||||
EXPECT_NEAR(expected, actual, kEpsilon);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(OopPixelTest, DrawGainmapImageFiltering) {
|
||||
constexpr gfx::Size kSize(4, 4);
|
||||
constexpr gfx::Rect kRect(kSize);
|
||||
|
@ -150,12 +150,27 @@ void DrawGainmapImageRect(SkCanvas* canvas,
|
||||
recorder);
|
||||
}
|
||||
|
||||
// SkGainmapShader will internally use SkImage::makeRawShader, which does
|
||||
// not support cubic filtering. Disable cubic filtering here.
|
||||
// https://crbug.com/374783345
|
||||
std::vector<SkSamplingOptions> tile_sampling = {sampling, sampling};
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
if (!tile_source_images[i] || !tile_sampling[i].useCubic) {
|
||||
continue;
|
||||
}
|
||||
tile_sampling[i] = SkSamplingOptions(SkFilterMode::kLinear,
|
||||
tile_source_images[i]->hasMipmaps()
|
||||
? SkMipmapMode::kLinear
|
||||
: SkMipmapMode::kNone);
|
||||
}
|
||||
|
||||
// Draw the tile.
|
||||
SkPaint tile_paint = paint;
|
||||
auto shader = SkGainmapShader::Make(
|
||||
tile_source_images[0], tile_source_rects[0], sampling,
|
||||
tile_source_images[1], tile_source_rects[1], sampling, gainmap_info,
|
||||
tile_dest_rect, hdr_headroom, canvas->imageInfo().refColorSpace());
|
||||
tile_source_images[0], tile_source_rects[0], tile_sampling[0],
|
||||
tile_source_images[1], tile_source_rects[1], tile_sampling[1],
|
||||
gainmap_info, tile_dest_rect, hdr_headroom,
|
||||
canvas->imageInfo().refColorSpace());
|
||||
tile_paint.setShader(std::move(shader));
|
||||
canvas->drawRect(tile_dest_rect, tile_paint);
|
||||
}
|
||||
|
Reference in New Issue
Block a user