Added patch to improve performance of bilinear bitmap scaling.

This commit is contained in:
Sebastian Lackner 2017-03-20 18:01:06 +01:00
parent 3e2e449d4e
commit 12f8688fc5
6 changed files with 314 additions and 0 deletions

View File

@ -0,0 +1,29 @@
From f7c317dac3581075e75168ce50c4523973422384 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Sun, 5 Mar 2017 12:55:51 +0800
Subject: gdiplus: Change the order of x/y loops in the scaler.
This improves performance by about 5%.
---
dlls/gdiplus/graphics.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 142b68115e..02d699b00b 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -3043,9 +3043,9 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
y_dx = dst_to_src_points[2].X - dst_to_src_points[0].X;
y_dy = dst_to_src_points[2].Y - dst_to_src_points[0].Y;
- for (x=dst_area.left; x<dst_area.right; x++)
+ for (y=dst_area.top; y<dst_area.bottom; y++)
{
- for (y=dst_area.top; y<dst_area.bottom; y++)
+ for (x=dst_area.left; x<dst_area.right; x++)
{
GpPointF src_pointf;
ARGB *dst_color;
--
2.11.0

View File

@ -0,0 +1,65 @@
From 04aee185cec481587e66fd410cf6ed2b6b6e2f90 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Sun, 5 Mar 2017 13:07:43 +0800
Subject: gdiplus: Change multiplications by additions in the x/y scaler loops.
This should imrove performance when floating point math will be replaced
by fixed point calculations.
---
dlls/gdiplus/graphics.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 02d699b00b..ef26887d14 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -3026,6 +3026,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
if (do_resampling)
{
+ REAL delta_xx, delta_xy, delta_yx, delta_yy;
+
/* Transform the bits as needed to the destination. */
dst_data = dst_dyn_data = heap_alloc_zero(sizeof(ARGB) * (dst_area.right - dst_area.left) * (dst_area.bottom - dst_area.top));
if (!dst_data)
@@ -3043,15 +3045,21 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
y_dx = dst_to_src_points[2].X - dst_to_src_points[0].X;
y_dy = dst_to_src_points[2].Y - dst_to_src_points[0].Y;
+ delta_yy = dst_area.top * y_dy;
+ delta_yx = dst_area.top * y_dx;
+
for (y=dst_area.top; y<dst_area.bottom; y++)
{
+ delta_xx = dst_area.left * x_dx;
+ delta_xy = dst_area.left * x_dy;
+
for (x=dst_area.left; x<dst_area.right; x++)
{
GpPointF src_pointf;
ARGB *dst_color;
- src_pointf.X = dst_to_src_points[0].X + x * x_dx + y * y_dx;
- src_pointf.Y = dst_to_src_points[0].Y + x * x_dy + y * y_dy;
+ src_pointf.X = dst_to_src_points[0].X + delta_xx + delta_yx;
+ src_pointf.Y = dst_to_src_points[0].Y + delta_xy + delta_yy;
dst_color = (ARGB*)(dst_data + dst_stride * (y - dst_area.top) + sizeof(ARGB) * (x - dst_area.left));
@@ -3060,7 +3068,13 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
imageAttributes, interpolation, offset_mode);
else
*dst_color = 0;
+
+ delta_xx += x_dx;
+ delta_yx += y_dx;
}
+
+ delta_xy += x_dy;
+ delta_yy += y_dy;
}
}
else
--
2.11.0

View File

@ -0,0 +1,57 @@
From f1b82c151d064eeafe234cdd95a4b29d7000232a Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Sun, 5 Mar 2017 13:18:21 +0800
Subject: gdiplus: Remove ceilf/floorf calls from bilinear scaler. (v2)
This improves performance by about 55%.
---
dlls/gdiplus/graphics.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index ef26887d14..58cfebb923 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -526,7 +526,7 @@ static ARGB blend_colors(ARGB start, ARGB end, REAL position)
INT start_a, end_a, final_a;
INT pos;
- pos = gdip_round(position * 0xff);
+ pos = (INT)(position * 255.0f + 0.5f);
start_a = ((start >> 24) & 0xff) * (pos ^ 0xff);
end_a = ((end >> 24) & 0xff) * pos;
@@ -928,6 +928,11 @@ static ARGB sample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT wi
return ((DWORD*)(bits))[(x - src_rect->X) + (y - src_rect->Y) * src_rect->Width];
}
+static FORCEINLINE int positive_ceilf(float f)
+{
+ return f - (int)f > 0.0f ? f + 1.0f : f;
+}
+
static ARGB resample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT width,
UINT height, GpPointF *point, GDIPCONST GpImageAttributes *attributes,
InterpolationMode interpolation, PixelOffsetMode offset_mode)
@@ -948,12 +953,12 @@ static ARGB resample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT
ARGB top, bottom;
float x_offset;
- leftxf = floorf(point->X);
- leftx = (INT)leftxf;
- rightx = (INT)ceilf(point->X);
- topyf = floorf(point->Y);
- topy = (INT)topyf;
- bottomy = (INT)ceilf(point->Y);
+ leftx = (INT)point->X;
+ leftxf = (REAL)leftx;
+ rightx = positive_ceilf(point->X);
+ topy = (INT)point->Y;
+ topyf = (REAL)topy;
+ bottomy = positive_ceilf(point->Y);
if (leftx == rightx && topy == bottomy)
return sample_bitmap_pixel(src_rect, bits, width, height,
--
2.11.0

View File

@ -0,0 +1,140 @@
From 37b9499d8da295cd8819d85e9a563629ef13f22e Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Sun, 5 Mar 2017 14:34:51 +0800
Subject: gdiplus: Prefer using pre-multiplied ARGB data in the scaler.
This further improves performance by about 20%.
---
dlls/gdiplus/graphics.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 91 insertions(+), 3 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 58cfebb923..bdee2e8318 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -521,6 +521,17 @@ static GpStatus alpha_blend_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
return alpha_blend_pixels_hrgn(graphics, dst_x, dst_y, src, src_width, src_height, src_stride, NULL, fmt);
}
+/* NOTE: start and end pixels must be in pre-multiplied ARGB format */
+static FORCEINLINE ARGB blend_colors_premult(ARGB start, ARGB end, REAL position)
+{
+ UINT pos = position * 255.0f + 0.5f;
+ return
+ (((((start >> 24) ) << 8) + (((end >> 24) ) - ((start >> 24) )) * pos) >> 8) << 24 |
+ (((((start >> 16) & 0xff) << 8) + (((end >> 16) & 0xff) - ((start >> 16) & 0xff)) * pos) >> 8) << 16 |
+ (((((start >> 8) & 0xff) << 8) + (((end >> 8) & 0xff) - ((start >> 8) & 0xff)) * pos) >> 8) << 8 |
+ (((((start ) & 0xff) << 8) + (((end ) & 0xff) - ((start ) & 0xff)) * pos) >> 8);
+}
+
static ARGB blend_colors(ARGB start, ARGB end, REAL position)
{
INT start_a, end_a, final_a;
@@ -1002,6 +1013,75 @@ static ARGB resample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT
}
}
+static ARGB resample_bitmap_pixel_premult(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT width,
+ UINT height, GpPointF *point, GDIPCONST GpImageAttributes *attributes,
+ InterpolationMode interpolation, PixelOffsetMode offset_mode)
+{
+ static int fixme;
+
+ switch (interpolation)
+ {
+ default:
+ if (!fixme++)
+ FIXME("Unimplemented interpolation %i\n", interpolation);
+ /* fall-through */
+ case InterpolationModeBilinear:
+ {
+ REAL leftxf, topyf;
+ INT leftx, rightx, topy, bottomy;
+ ARGB topleft, topright, bottomleft, bottomright;
+ ARGB top, bottom;
+ float x_offset;
+
+ leftx = (INT)point->X;
+ leftxf = (REAL)leftx;
+ rightx = positive_ceilf(point->X);
+ topy = (INT)point->Y;
+ topyf = (REAL)topy;
+ bottomy = positive_ceilf(point->Y);
+
+ if (leftx == rightx && topy == bottomy)
+ return sample_bitmap_pixel(src_rect, bits, width, height,
+ leftx, topy, attributes);
+
+ topleft = sample_bitmap_pixel(src_rect, bits, width, height,
+ leftx, topy, attributes);
+ topright = sample_bitmap_pixel(src_rect, bits, width, height,
+ rightx, topy, attributes);
+ bottomleft = sample_bitmap_pixel(src_rect, bits, width, height,
+ leftx, bottomy, attributes);
+ bottomright = sample_bitmap_pixel(src_rect, bits, width, height,
+ rightx, bottomy, attributes);
+
+ x_offset = point->X - leftxf;
+ top = blend_colors_premult(topleft, topright, x_offset);
+ bottom = blend_colors_premult(bottomleft, bottomright, x_offset);
+
+ return blend_colors_premult(top, bottom, point->Y - topyf);
+ }
+ case InterpolationModeNearestNeighbor:
+ {
+ FLOAT pixel_offset;
+ switch (offset_mode)
+ {
+ default:
+ case PixelOffsetModeNone:
+ case PixelOffsetModeHighSpeed:
+ pixel_offset = 0.5;
+ break;
+
+ case PixelOffsetModeHalf:
+ case PixelOffsetModeHighQuality:
+ pixel_offset = 0.0;
+ break;
+ }
+ return sample_bitmap_pixel(src_rect, bits, width, height,
+ floorf(point->X + pixel_offset), point->Y + pixel_offset, attributes);
+ }
+
+ }
+}
+
static REAL intersect_line_scanline(const GpPointF *p1, const GpPointF *p2, REAL y)
{
return (p1->X - p2->X) * (p2->Y - y) / (p2->Y - p1->Y) + p2->X;
@@ -3010,8 +3090,10 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
lockeddata.Scan0 = src_data;
if (!do_resampling && bitmap->format == PixelFormat32bppPARGB)
lockeddata.PixelFormat = apply_image_attributes(imageAttributes, NULL, 0, 0, 0, ColorAdjustTypeBitmap, bitmap->format);
- else
+ else if (imageAttributes != &defaultImageAttributes)
lockeddata.PixelFormat = PixelFormat32bppARGB;
+ else
+ lockeddata.PixelFormat = PixelFormat32bppPARGB;
stat = GdipBitmapLockBits(bitmap, &src_area, ImageLockModeRead|ImageLockModeUserInputBuf,
lockeddata.PixelFormat, &lockeddata);
@@ -3069,8 +3151,14 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
dst_color = (ARGB*)(dst_data + dst_stride * (y - dst_area.top) + sizeof(ARGB) * (x - dst_area.left));
if (src_pointf.X >= srcx && src_pointf.X < srcx + srcwidth && src_pointf.Y >= srcy && src_pointf.Y < srcy+srcheight)
- *dst_color = resample_bitmap_pixel(&src_area, src_data, bitmap->width, bitmap->height, &src_pointf,
- imageAttributes, interpolation, offset_mode);
+ {
+ if (lockeddata.PixelFormat != PixelFormat32bppPARGB)
+ *dst_color = resample_bitmap_pixel(&src_area, src_data, bitmap->width, bitmap->height, &src_pointf,
+ imageAttributes, interpolation, offset_mode);
+ else
+ *dst_color = resample_bitmap_pixel_premult(&src_area, src_data, bitmap->width, bitmap->height, &src_pointf,
+ imageAttributes, interpolation, offset_mode);
+ }
else
*dst_color = 0;
--
2.11.0

View File

@ -0,0 +1 @@
Fixes: Improve performance of bilinear bitmap scaling

View File

@ -163,6 +163,7 @@ patch_enable_all ()
enable_gdi32_Symbol_Truetype_Font="$1"
enable_gdiplus_DC_Handling="$1"
enable_gdiplus_Grayscale_PNG="$1"
enable_gdiplus_Performance_Improvements="$1"
enable_hal_KeQueryPerformanceCounter="$1"
enable_hnetcfg_INetFwAuthorizedApplication="$1"
enable_ieframe_IViewObject_Draw="$1"
@ -713,6 +714,9 @@ patch_enable ()
gdiplus-Grayscale_PNG)
enable_gdiplus_Grayscale_PNG="$2"
;;
gdiplus-Performance-Improvements)
enable_gdiplus_Performance_Improvements="$2"
;;
hal-KeQueryPerformanceCounter)
enable_hal_KeQueryPerformanceCounter="$2"
;;
@ -4202,6 +4206,24 @@ if test "$enable_gdiplus_Grayscale_PNG" -eq 1; then
) >> "$patchlist"
fi
# Patchset gdiplus-Performance-Improvements
# |
# | Modified files:
# | * dlls/gdiplus/graphics.c
# |
if test "$enable_gdiplus_Performance_Improvements" -eq 1; then
patch_apply gdiplus-Performance-Improvements/0001-gdiplus-Change-the-order-of-x-y-loops-in-the-scaler.patch
patch_apply gdiplus-Performance-Improvements/0002-gdiplus-Change-multiplications-by-additions-in-the-x.patch
patch_apply gdiplus-Performance-Improvements/0003-gdiplus-Remove-ceilf-floorf-calls-from-bilinear-scal.patch
patch_apply gdiplus-Performance-Improvements/0004-gdiplus-Prefer-using-pre-multiplied-ARGB-data-in-the.patch
(
printf '%s\n' '+ { "Dmitry Timoshkov", "gdiplus: Change the order of x/y loops in the scaler.", 1 },';
printf '%s\n' '+ { "Dmitry Timoshkov", "gdiplus: Change multiplications by additions in the x/y scaler loops.", 1 },';
printf '%s\n' '+ { "Dmitry Timoshkov", "gdiplus: Remove ceilf/floorf calls from bilinear scaler.", 2 },';
printf '%s\n' '+ { "Dmitry Timoshkov", "gdiplus: Prefer using pre-multiplied ARGB data in the scaler.", 1 },';
) >> "$patchlist"
fi
# Patchset hal-KeQueryPerformanceCounter
# |
# | This patchset fixes the following Wine bugs: