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>();
|
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
|
||||||
display_item_list->StartPaint();
|
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,
|
display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, sampling,
|
||||||
nullptr);
|
nullptr);
|
||||||
display_item_list->EndPaintOfUnpaired(kRect);
|
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) {
|
TEST_F(OopPixelTest, DrawGainmapImageFiltering) {
|
||||||
constexpr gfx::Size kSize(4, 4);
|
constexpr gfx::Size kSize(4, 4);
|
||||||
constexpr gfx::Rect kRect(kSize);
|
constexpr gfx::Rect kRect(kSize);
|
||||||
|
@@ -150,12 +150,27 @@ void DrawGainmapImageRect(SkCanvas* canvas,
|
|||||||
recorder);
|
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.
|
// Draw the tile.
|
||||||
SkPaint tile_paint = paint;
|
SkPaint tile_paint = paint;
|
||||||
auto shader = SkGainmapShader::Make(
|
auto shader = SkGainmapShader::Make(
|
||||||
tile_source_images[0], tile_source_rects[0], sampling,
|
tile_source_images[0], tile_source_rects[0], tile_sampling[0],
|
||||||
tile_source_images[1], tile_source_rects[1], sampling, gainmap_info,
|
tile_source_images[1], tile_source_rects[1], tile_sampling[1],
|
||||||
tile_dest_rect, hdr_headroom, canvas->imageInfo().refColorSpace());
|
gainmap_info, tile_dest_rect, hdr_headroom,
|
||||||
|
canvas->imageInfo().refColorSpace());
|
||||||
tile_paint.setShader(std::move(shader));
|
tile_paint.setShader(std::move(shader));
|
||||||
canvas->drawRect(tile_dest_rect, tile_paint);
|
canvas->drawRect(tile_dest_rect, tile_paint);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user