Commit 02dbe866 authored by Reza.Zakerinasab's avatar Reza.Zakerinasab Committed by Commit Bot

Address canvas perf regressions in createImageBitmapFromImageData

This change tries to address the perf regression reported for
createImageBitmapFromImageData canvas perf test. This change performs
the premul operation in ImageData in advance, instead of doing that after
creating the ImageBitmap. This has resulted in ~60% perf improvement
on the local Linux machine, so it hopefully must address the regressions.

Bug: 782813,787772,787811
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2
Change-Id: If0f02d99677348d49cc9d16e910113b4250afb69
Reviewed-on: https://chromium-review.googlesource.com/802855Reviewed-by: default avatarJustin Novosad <junov@chromium.org>
Commit-Queue: Mohammad Reza Zakerinasab <zakerinasab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#521476}
parent 5ca41a08
......@@ -746,7 +746,8 @@ bool ImageData::ImageDataInCanvasColorSettings(
CanvasPixelFormat canvas_pixel_format,
unsigned char* converted_pixels,
DataU8ColorType u8_color_type,
const IntRect* src_rect) {
const IntRect* src_rect,
const AlphaDisposition alpha_disposition) {
if (!data_ && !data_u16_ && !data_f32_)
return false;
......@@ -764,6 +765,7 @@ bool ImageData::ImageDataInCanvasColorSettings(
// if color conversion is not needed, copy data into pixel buffer.
if (!src_color_space.get() && !dst_color_space.get() && data_) {
int num_pixels = width() * height();
SwizzleIfNeeded(u8_color_type, crop_rect);
if (crop_rect) {
unsigned char* src_data =
......@@ -778,11 +780,23 @@ bool ImageData::ImageDataInCanvasColorSettings(
src_index += src_row_stride;
dst_index += dst_row_stride;
}
num_pixels = crop_rect->Width() * crop_rect->Height();
} else {
memcpy(converted_pixels, data_->Data(), data_->length());
}
bool conversion_result = true;
if (alpha_disposition == kPremultiplyAlpha) {
std::unique_ptr<SkColorSpaceXform> xform =
SkColorSpaceXform::New(SkColorSpace::MakeSRGBLinear().get(),
SkColorSpace::MakeSRGBLinear().get());
SkColorSpaceXform::ColorFormat color_format =
SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
conversion_result =
xform->apply(color_format, converted_pixels, color_format,
converted_pixels, num_pixels, kPremul_SkAlphaType);
}
SwizzleIfNeeded(u8_color_type, crop_rect);
return true;
return conversion_result;
}
bool conversion_result = false;
......@@ -806,6 +820,9 @@ bool ImageData::ImageDataInCanvasColorSettings(
: SkColorSpaceXform::ColorFormat::kBGRA_8888_ColorFormat;
if (canvas_pixel_format == kF16CanvasPixelFormat)
dst_color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat;
SkAlphaType alpha_type = (alpha_disposition == kPremultiplyAlpha)
? kPremul_SkAlphaType
: kUnpremul_SkAlphaType;
// SkColorSpaceXform only accepts big-endian integers when source data is
// uint16. Since ImageData is always little-endian, we need to convert back
......@@ -827,17 +844,16 @@ bool ImageData::ImageDataInCanvasColorSettings(
for (int i = 0; i < crop_rect->Height(); i++) {
conversion_result &=
xform->apply(dst_color_format, dst_data + dst_index, src_color_format,
src_data + src_index, crop_rect->Width(),
SkAlphaType::kUnpremul_SkAlphaType);
src_data + src_index, crop_rect->Width(), alpha_type);
if (!conversion_result)
break;
src_index += src_row_stride;
dst_index += dst_row_stride;
}
} else {
conversion_result = xform->apply(dst_color_format, converted_pixels,
src_color_format, src_data, size_.Area(),
SkAlphaType::kUnpremul_SkAlphaType);
conversion_result =
xform->apply(dst_color_format, converted_pixels, src_color_format,
src_data, size_.Area(), alpha_type);
}
SwapU16EndiannessForSkColorSpaceXform(crop_rect);
......
......@@ -138,11 +138,13 @@ class CORE_EXPORT ImageData final : public ScriptWrappable,
// For example, if ImageDataInCanvasColorSettings() is called to fill an
// ImageBuffer, kRGBAColorType should be used. If the converted pixels are
// used to create an ImageBitmap, kN32ColorType should be used.
bool ImageDataInCanvasColorSettings(CanvasColorSpace,
CanvasPixelFormat,
unsigned char* converted_pixels,
DataU8ColorType,
const IntRect* = nullptr);
bool ImageDataInCanvasColorSettings(
CanvasColorSpace,
CanvasPixelFormat,
unsigned char* converted_pixels,
DataU8ColorType,
const IntRect* = nullptr,
const AlphaDisposition = kDontPremultiplyAlpha);
// ImageBitmapSource implementation
IntSize BitmapSourceSize() const override { return size_; }
......
......@@ -284,6 +284,11 @@ scoped_refptr<StaticBitmapImage> GetImageWithAlphaDisposition(
info = info.makeAlphaType(alpha_type);
// For premul to unpremul, we have to readback the pixels.
// For unpremul to premul, we can either readback the pixels or draw onto a
// surface. As shown in
// https://fiddle.skia.org/c/1ec3c61ed08f7863d43b9f49ab120a0a, drawing on a
// surface and getting a snapshot is slower if the image is small. Therefore,
// for small images (< 128x128 pixels), we still do read back.
if (alpha_type == kUnpremul_SkAlphaType ||
(image->width() * image->height() < 16384)) {
// Set the color space of the ImageInfo to nullptr to unpremul in gamma
......@@ -295,12 +300,6 @@ scoped_refptr<StaticBitmapImage> GetImageWithAlphaDisposition(
return NewImageFromRaster(info, std::move(dst_pixels));
}
// For unpremul to premul, we can either readback the pixels or draw onto a
// surface. As shown in
// https://fiddle.skia.org/c/1ec3c61ed08f7863d43b9f49ab120a0a, drawing on a
// surface and getting a snapshot is slower if the image is small. Therefore,
// for small images (< 128x128 pixels), we still do read back.
// Draw on a surface. Avoid sRGB gamma transfer curve.
if (SkColorSpace::Equals(info.colorSpace(), SkColorSpace::MakeSRGB().get()))
info = info.makeColorSpace(nullptr);
......@@ -766,13 +765,17 @@ ImageBitmap::ImageBitmap(ImageData* data,
if (!data->ImageDataInCanvasColorSettings(
parsed_options.color_params.ColorSpace(),
parsed_options.color_params.PixelFormat(), image_pixels->Data(),
kN32ColorType, &src_rect))
kN32ColorType, &src_rect,
parsed_options.premultiply_alpha ? kPremultiplyAlpha
: kDontPremultiplyAlpha))
return;
// Create Image object
SkImageInfo info = SkImageInfo::Make(
src_rect.Width(), src_rect.Height(),
parsed_options.color_params.GetSkColorType(), kUnpremul_SkAlphaType,
parsed_options.color_params.GetSkColorType(),
parsed_options.premultiply_alpha ? kPremul_SkAlphaType
: kUnpremul_SkAlphaType,
parsed_options.color_params.GetSkColorSpaceForSkSurfaces());
image_ = NewImageFromRaster(info, std::move(image_pixels));
if (!image_)
......@@ -791,12 +794,6 @@ ImageBitmap::ImageBitmap(ImageData* data,
if (!image_)
return;
// premultiply if needed
if (parsed_options.premultiply_alpha)
image_ = GetImageWithAlphaDisposition(std::move(image_), kPremultiplyAlpha);
if (!image_)
return;
// flip if needed
if (parsed_options.flip_y)
image_ = FlipImageVertically(std::move(image_), parsed_options);
......
......@@ -28,11 +28,6 @@ class ImageData;
class ImageDecoder;
class OffscreenCanvas;
enum AlphaDisposition {
kPremultiplyAlpha,
kDontPremultiplyAlpha,
};
enum ColorSpaceInfoUpdate {
kUpdateColorSpaceInformation,
kDontUpdateColorSpaceInformation,
......
......@@ -35,6 +35,11 @@
namespace blink {
enum AlphaDisposition {
kPremultiplyAlpha,
kDontPremultiplyAlpha,
};
enum DataU8ColorType {
kRGBAColorType,
kN32ColorType,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment