By not using floorf from external library ucrtbase.dll the performance of GdipDrawImagePointsRect was improved.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53947
After applying patch the game performance is similar to native gdiplus.dll.
Result of oprofile before patch: ``` samples % image name app name symbol name 895705 33.4761 ucrtbase.dll.so wine floor 351683 13.1438 no-vmlinux wine /no-vmlinux 330995 12.3706 gdiplus.dll.so wine resample_bitmap_pixel 300093 11.2157 win32u.so wine blend_rects_8888 272645 10.1898 gdiplus.dll.so wine GdipDrawImagePointsRect 137421 5.1360 gdiplus.dll.so wine sample_bitmap_pixel 112476 4.2037 gdiplus.dll.so wine convert_32bppARGB_to_32bppPARGB 35455 1.3251 no-vmlinux wineserver /no-vmlinux 35223 1.3164 no-vmlinux wine64-preloader /no-vmlinux 30252 1.1306 libc.so.6 wine /usr/lib/i386-linux-gnu/libc.so.6 ``` and after patch: ``` samples % image name app name symbol name 248581 18.3279 no-vmlinux wine /no-vmlinux 200141 14.7564 gdiplus.dll.so wine resample_bitmap_pixel 199840 14.7342 win32u.so wine blend_rects_8888 179135 13.2076 gdiplus.dll.so wine GdipDrawImagePointsRect 105785 7.7995 no-vmlinux wine-preloader /no-vmlinux 89534 6.6013 gdiplus.dll.so wine sample_bitmap_pixel 83947 6.1894 no-vmlinux wine64-preloader /no-vmlinux 74132 5.4658 gdiplus.dll.so wine convert_32bppARGB_to_32bppPARGB 22978 1.6942 anon (tgid:374066 range:0x7bc10000-0x7bffffff) wine anon (tgid:374066 range:0x7bc10000-0x7bffffff) 19747 1.4559 libc.so.6 wine /usr/lib/i386-linux-gnu/libc.so.6 14570 1.0742 win32u.so wine solid_rects_32 ```
Can we stop using floorf and ceilf from `math.h`?
-- v3: gdiplus: Boost performance of GdipDrawImagePointsRect.
From: Bartosz Kosiorek gang65@poczta.onet.pl
By not using floorf from external library ucrtbase.dll the performance of GdipDrawImagePointsRect was improved.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53947 --- dlls/gdiplus/graphics.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 371629a5bef..5647db3d29e 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -1055,22 +1055,38 @@ static ARGB resample_bitmap_pixel(GDIPCONST GpRect *src_rect, LPBYTE bits, UINT } case InterpolationModeNearestNeighbor: { - FLOAT pixel_offset; + /* Using floorf from ucrtbase.dll is extremaly slow compared to own implementation (casting to INT) */ + INT pixel_with_offset_x, pixel_with_offset_y; switch (offset_mode) { default: case PixelOffsetModeNone: case PixelOffsetModeHighSpeed: - pixel_offset = 0.5; - break; + if (point->X >= 0.0f) + pixel_with_offset_x = (INT)(point->X + 0.5f); + else + pixel_with_offset_x = (INT)(point->X - 0.5f);
+ if (point->Y >= 0.0f) + pixel_with_offset_y = (INT)(point->Y + 0.5f); + else + pixel_with_offset_y = (INT)(point->Y - 0.5f); + break; case PixelOffsetModeHalf: case PixelOffsetModeHighQuality: - pixel_offset = 0.0; + if (point->X >= 0.0f) + pixel_with_offset_x = (INT)(point->X); + else + pixel_with_offset_x = (INT)(point->X - 1.0f); + + if (point->Y >= 0.0f) + pixel_with_offset_y = (INT)(point->Y); + else + pixel_with_offset_y = (INT)(point->Y - 1.0f); break; } return sample_bitmap_pixel(src_rect, bits, width, height, - floorf(point->X + pixel_offset), floorf(point->Y + pixel_offset), attributes); + pixel_with_offset_x, pixel_with_offset_y, attributes); }
}
On Wed Nov 15 00:13:50 2023 +0000, Fabian Maurer wrote:
Okay, I didn't notice you secretly updated your patch to use floorf again. This completely negates the performance gains. FWIW, I created bug 55899 about a performance regression where the stack isn't aligned. Maybe this causes the issues with floor? Because having both your/mine patch for this issue and the one for bug 55899 doesn't make it any faster, only one is enough. But I'd lie if I said I know what#s going on here, I'm pretty confused.
The performance degradation is especially visible during intro, when the text is appearing. Due to different font used for Wine implementation, the size of the font and outline have some glithes:
![daily-wine-buildin](/uploads/510d8f93d9e67f772791f709a49f580a/daily-wine-buildin.png)
Here is the comparison with native gdiplus: ![daily-wine-native](/uploads/0e71fc66792b1de00439d33c6d282ced/daily-wine-native.png)
On Wed Nov 15 15:40:49 2023 +0000, Bartosz Kosiorek wrote:
I think yes. According to documentation:
Consider the pixel in the upper-left corner of an image with address
(0, 0). With PixelOffsetModeNone, the pixel covers the area between –0.5 and 0.5 in both the x and y directions; that is, the pixel center is at (0, 0). With PixelOffsetModeHalf, the pixel covers the area between 0 and 1 in both the x and y directions; that is, the pixel center is at (0.5, 0.5). https://learn.microsoft.com/en-us/windows/win32/api/gdiplusenums/ne-gdipluse...
Yes, it does. In the case of actual interpolation, it's more obvious, but for nearest neighbor something still has to do this work to properly map the float coordinates to integers.
On Wed Nov 15 07:17:12 2023 +0000, Bartosz Kosiorek wrote:
The performance degradation is especially visible during intro, when the text is appearing. Due to different font used for Wine implementation, the size of the font and outline have some glithes: ![daily-wine-buildin](/uploads/510d8f93d9e67f772791f709a49f580a/daily-wine-buildin.png) Here is the comparison with native gdiplus: ![daily-wine-native](/uploads/0e71fc66792b1de00439d33c6d282ced/daily-wine-native.png)
It sounds like this is more related to Wine's crt than gdiplus so the fix should probably be there.