From e63752e6bb886d83af0c22faa673ea4cf99729f0 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 17 Mar 2015 14:07:37 +0100 Subject: Remove table of mostly null pointers The patch moves the initialization of the format to format blend tables to runtime, so we only have to explicitly set the values that are not null. This removes most of the lines in qblendfunctions.cpp. Change-Id: Ie017f380ff11cfb764a631cfea7626786731b5fb Reviewed-by: Gunnar Sletta --- src/gui/painting/qblendfunctions.cpp | 2136 ++-------------------------------- 1 file changed, 70 insertions(+), 2066 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp index 478fe6564c..b3710411c9 100644 --- a/src/gui/painting/qblendfunctions.cpp +++ b/src/gui/painting/qblendfunctions.cpp @@ -432,10 +432,10 @@ static void qt_blend_argb32pm_on_a2rgb30pm(uchar *destPixels, int dbpl, } template -void qt_blend_rgb32_on_rgb30(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha) +static void qt_blend_rgb32_on_rgb30(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) { #ifdef QT_DEBUG_DRAW fprintf(stdout, "qt_blend_rgb32_on_rgb30: dst=(%p, %d), src=(%p, %d), dim=(%d, %d) alpha=%d\n", @@ -496,10 +496,10 @@ static void qt_blend_a2rgb30pm_on_a2rgb30pm(uchar *destPixels, int dbpl, } -void qt_blend_rgb30_on_rgb30(uchar *destPixels, int dbpl, - const uchar *srcPixels, int sbpl, - int w, int h, - int const_alpha) +static void qt_blend_rgb30_on_rgb30(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha) { #ifdef QT_DEBUG_DRAW fprintf(stdout, "qt_blend_rgb30_on_rgb30: dst=(%p, %d), src=(%p, %d), dim=(%d, %d) alpha=%d\n", @@ -740,2071 +740,75 @@ void qt_transform_image_argb32_on_argb32(uchar *destPixels, int dbpl, } } -SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] = { - { // Format_Invalid - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGRs30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Mono - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_MonoLSB - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Indexed8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_scale_image_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_scale_image_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_scale_image_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_scale_image_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB16 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - qt_scale_image_argb32_on_rgb16, // Format_ARGB32_Premultiplied, - qt_scale_image_rgb16_on_rgb16, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8565_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB666 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB6666_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB555 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8555_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB444 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB4444_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBX8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_scale_image_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_scale_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, -#endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_scale_image_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_scale_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, -#endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_BGR30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_A2BGR30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_A2RGB30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Alpha8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Grayscale8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - } -}; - +SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats]; +SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats]; +SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFormats]; -SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] = { - { // Format_Invalid - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Mono - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_MonoLSB - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Indexed8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB16 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb16, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32_on_rgb16, // Format_ARGB32_Premultiplied, - qt_blend_rgb16_on_rgb16, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8565_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB666 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB6666_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB555 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8555_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB444 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB4444_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBX8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_blend_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_blend_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, -#endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, +void qInitBlendFunctions() +{ + qScaleFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_scale_image_rgb32_on_rgb32; + qScaleFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32; + qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_scale_image_rgb32_on_rgb32; + qScaleFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_argb32; + qScaleFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_scale_image_argb32_on_rgb16; + qScaleFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_scale_image_rgb16_on_rgb16; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_blend_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_blend_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, + qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_scale_image_rgb32_on_rgb32; + qScaleFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32; + qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_scale_image_rgb32_on_rgb32; + qScaleFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_scale_image_argb32_on_argb32; #endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_BGR30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb30, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32pm_on_a2rgb30pm, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - qt_blend_rgb30_on_rgb30, // Format_RGB30, - qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_RGB30, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - 0, 0, - }, - { // Format_A2BGR30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb30, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32pm_on_a2rgb30pm, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - qt_blend_rgb30_on_rgb30, // Format_BGR30, - qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2BGR30_Premultiplied, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_RGB30, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - 0, 0, - }, - { // Format_RGB30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb30, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32pm_on_a2rgb30pm, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_BGR30, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2BGR30_Premultiplied, - qt_blend_rgb30_on_rgb30, // Format_RGB30, - qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - 0, 0, - }, - { // Format_A2RGB30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_blend_rgb32_on_rgb30, // Format_RGB32, - 0, // Format_ARGB32, - qt_blend_argb32pm_on_a2rgb30pm, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_BGR30, - qt_blend_a2bgr30pm_on_a2rgb30pm, // Format_A2BGR30_Premultiplied, - qt_blend_rgb30_on_rgb30, // Format_RGB30, - qt_blend_a2rgb30pm_on_a2rgb30pm, // Format_A2RGB30_Premultiplied, - 0, 0, - }, - { // Format_Alpha8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Grayscale8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - } -}; -SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFormats] = { - { // Format_Invalid - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Mono - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_MonoLSB - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Indexed8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_transform_image_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_transform_image_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB32_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - qt_transform_image_rgb32_on_rgb32, // Format_RGB32, - 0, // Format_ARGB32, - qt_transform_image_argb32_on_argb32, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB16 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - qt_transform_image_argb32_on_rgb16, // Format_ARGB32_Premultiplied, - qt_transform_image_rgb16_on_rgb16, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8565_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB666 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB6666_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB555 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB8555_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB444 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_ARGB4444_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBX8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, + qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32; + qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32; + qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb16; + qBlendFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_rgb16; + qBlendFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_blend_rgb16_on_rgb16; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_transform_image_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_transform_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32; + qBlendFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_blend_rgb32_on_rgb32; + qBlendFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_blend_argb32_on_argb32; #endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGBA8888_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, + qBlendFunctions[QImage::Format_BGR30][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_BGR30] = qt_blend_rgb30_on_rgb30; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_RGB30] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_BGR30][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_BGR30] = qt_blend_rgb30_on_rgb30; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_RGB30] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2BGR30_Premultiplied][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_BGR30] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_RGB30] = qt_blend_rgb30_on_rgb30; + qBlendFunctions[QImage::Format_RGB30][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb30; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_BGR30] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_A2BGR30_Premultiplied] = qt_blend_a2bgr30pm_on_a2rgb30pm; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_RGB30] = qt_blend_rgb30_on_rgb30; + qBlendFunctions[QImage::Format_A2RGB30_Premultiplied][QImage::Format_A2RGB30_Premultiplied] = qt_blend_a2rgb30pm_on_a2rgb30pm; + + qTransformFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_transform_image_rgb32_on_rgb32; + qTransformFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_argb32; + qTransformFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_transform_image_rgb32_on_rgb32; + qTransformFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_argb32; + qTransformFunctions[QImage::Format_RGB16][QImage::Format_ARGB32_Premultiplied] = qt_transform_image_argb32_on_rgb16; + qTransformFunctions[QImage::Format_RGB16][QImage::Format_RGB16] = qt_transform_image_rgb16_on_rgb16; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - qt_transform_image_rgb32_on_rgb32, // Format_RGBX8888, - 0, // Format_RGBA8888, - qt_transform_image_argb32_on_argb32, // Format_RGBA8888_Premultiplied, -#else - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, + qTransformFunctions[QImage::Format_RGBX8888][QImage::Format_RGBX8888] = qt_transform_image_rgb32_on_rgb32; + qTransformFunctions[QImage::Format_RGBX8888][QImage::Format_RGBA8888_Premultiplied] = qt_transform_image_argb32_on_argb32; + qTransformFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBX8888] = qt_transform_image_rgb32_on_rgb32; + qTransformFunctions[QImage::Format_RGBA8888_Premultiplied][QImage::Format_RGBA8888_Premultiplied] = qt_transform_image_argb32_on_argb32; #endif - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_BGR30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_A2BGR30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_RGB30 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_A2RGB30_Premultiplied - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Alpha8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, - { // Format_Grayscale8 - 0, // Format_Invalid, - 0, // Format_Mono, - 0, // Format_MonoLSB, - 0, // Format_Indexed8, - 0, // Format_RGB32, - 0, // Format_ARGB32, - 0, // Format_ARGB32_Premultiplied, - 0, // Format_RGB16, - 0, // Format_ARGB8565_Premultiplied, - 0, // Format_RGB666, - 0, // Format_ARGB6666_Premultiplied, - 0, // Format_RGB555, - 0, // Format_ARGB8555_Premultiplied, - 0, // Format_RGB888, - 0, // Format_RGB444, - 0, // Format_ARGB4444_Premultiplied, - 0, // Format_RGBX8888, - 0, // Format_RGBA8888, - 0, // Format_RGBA8888_Premultiplied, - 0, // Format_BGR30, - 0, // Format_A2BGR30_Premultiplied, - 0, // Format_RGB30, - 0, // Format_A2RGB30_Premultiplied, - 0, // Format_Alpha8 - 0, // Format_Grayscale8 - }, -}; +} QT_END_NAMESPACE -- cgit v1.2.3 From c52bcf733742837f7fbeedbb788c3c9285a24bb6 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 9 Mar 2015 17:32:15 +0100 Subject: Support gradients natively in the PDF generator Add native support for linear and radial gradients to our PDF generator. This fixes a couple of issues with both the quality of the generated PDFs as well as sizes of the files. Task-number: QTBUG-42758 Change-Id: Ib905457e11e4dc52443c76b3761bca8d1fbe9bfc Reviewed-by: Stephen Chu Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/qpdf.cpp | 490 +++++++++++++++++++++++++--------------------- src/gui/painting/qpdf_p.h | 13 +- 2 files changed, 270 insertions(+), 233 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index cc1ad02eee..3f2ebb92a0 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -66,12 +66,9 @@ QT_BEGIN_NAMESPACE inline QPaintEngine::PaintEngineFeatures qt_pdf_decide_features() { QPaintEngine::PaintEngineFeatures f = QPaintEngine::AllFeatures; - f &= ~(QPaintEngine::PorterDuff | QPaintEngine::PerspectiveTransform + f &= ~(QPaintEngine::PorterDuff + | QPaintEngine::PerspectiveTransform | QPaintEngine::ObjectBoundingModeGradients -#ifndef USE_NATIVE_GRADIENTS - | QPaintEngine::LinearGradientFill -#endif - | QPaintEngine::RadialGradientFill | QPaintEngine::ConicalGradientFill); return f; } @@ -548,189 +545,6 @@ QByteArray QPdf::patternForBrush(const QBrush &b) return pattern_for_brush[style]; } -#ifdef USE_NATIVE_GRADIENTS -static void writeTriangleLine(uchar *&data, int xpos, int ypos, int xoff, int yoff, uint rgb, uchar flag, bool alpha) -{ - data[0] = flag; - data[1] = (uchar)(xpos >> 16); - data[2] = (uchar)(xpos >> 8); - data[3] = (uchar)(xpos >> 0); - data[4] = (uchar)(ypos >> 16); - data[5] = (uchar)(ypos >> 8); - data[6] = (uchar)(ypos >> 0); - data += 7; - if (alpha) { - *data++ = (uchar)qAlpha(rgb); - } else { - *data++ = (uchar)qRed(rgb); - *data++ = (uchar)qGreen(rgb); - *data++ = (uchar)qBlue(rgb); - } - xpos += xoff; - ypos += yoff; - data[0] = flag; - data[1] = (uchar)(xpos >> 16); - data[2] = (uchar)(xpos >> 8); - data[3] = (uchar)(xpos >> 0); - data[4] = (uchar)(ypos >> 16); - data[5] = (uchar)(ypos >> 8); - data[6] = (uchar)(ypos >> 0); - data += 7; - if (alpha) { - *data++ = (uchar)qAlpha(rgb); - } else { - *data++ = (uchar)qRed(rgb); - *data++ = (uchar)qGreen(rgb); - *data++ = (uchar)qBlue(rgb); - } -} - - -QByteArray QPdf::generateLinearGradientShader(const QLinearGradient *gradient, const QPointF *page_rect, bool alpha) -{ - // generate list of triangles with colors - QPointF start = gradient->start(); - QPointF stop = gradient->finalStop(); - QGradientStops stops = gradient->stops(); - QPointF offset = stop - start; - QGradient::Spread spread = gradient->spread(); - - if (gradient->spread() == QGradient::ReflectSpread) { - offset *= 2; - for (int i = stops.size() - 2; i >= 0; --i) { - QGradientStop stop = stops.at(i); - stop.first = 2. - stop.first; - stops.append(stop); - } - for (int i = 0 ; i < stops.size(); ++i) - stops[i].first /= 2.; - } - - QPointF orthogonal(offset.y(), -offset.x()); - qreal length = offset.x()*offset.x() + offset.y()*offset.y(); - - // find the max and min values in offset and orth direction that are needed to cover - // the whole page - int off_min = INT_MAX; - int off_max = INT_MIN; - qreal ort_min = INT_MAX; - qreal ort_max = INT_MIN; - for (int i = 0; i < 4; ++i) { - qreal off = ((page_rect[i].x() - start.x()) * offset.x() + (page_rect[i].y() - start.y()) * offset.y())/length; - qreal ort = ((page_rect[i].x() - start.x()) * orthogonal.x() + (page_rect[i].y() - start.y()) * orthogonal.y())/length; - off_min = qMin(off_min, qFloor(off)); - off_max = qMax(off_max, qCeil(off)); - ort_min = qMin(ort_min, ort); - ort_max = qMax(ort_max, ort); - } - ort_min -= 1; - ort_max += 1; - - start += off_min * offset + ort_min * orthogonal; - orthogonal *= (ort_max - ort_min); - int num = off_max - off_min; - - QPointF gradient_rect[4] = { start, - start + orthogonal, - start + num*offset, - start + num*offset + orthogonal }; - qreal xmin = gradient_rect[0].x(); - qreal xmax = gradient_rect[0].x(); - qreal ymin = gradient_rect[0].y(); - qreal ymax = gradient_rect[0].y(); - for (int i = 1; i < 4; ++i) { - xmin = qMin(xmin, gradient_rect[i].x()); - xmax = qMax(xmax, gradient_rect[i].x()); - ymin = qMin(ymin, gradient_rect[i].y()); - ymax = qMax(ymax, gradient_rect[i].y()); - } - xmin -= 1000; - xmax += 1000; - ymin -= 1000; - ymax += 1000; - start -= QPointF(xmin, ymin); - qreal factor_x = qreal(1<<24)/(xmax - xmin); - qreal factor_y = qreal(1<<24)/(ymax - ymin); - int xoff = (int)(orthogonal.x()*factor_x); - int yoff = (int)(orthogonal.y()*factor_y); - - QByteArray triangles; - triangles.resize(spread == QGradient::PadSpread ? 20*(stops.size()+2) : 20*num*stops.size()); - uchar *data = (uchar *) triangles.data(); - if (spread == QGradient::PadSpread) { - if (off_min > 0 || off_max < 1) { - // linear gradient outside of page - const QGradientStop ¤t_stop = off_min > 0 ? stops.at(stops.size()-1) : stops.at(0); - uint rgb = current_stop.second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, 0, alpha); - start += num*offset; - xpos = (int)(start.x()*factor_x); - ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, 1, alpha); - } else { - int flag = 0; - if (off_min < 0) { - uint rgb = stops.at(0).second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, flag, alpha); - start -= off_min*offset; - flag = 1; - } - for (int s = 0; s < stops.size(); ++s) { - const QGradientStop ¤t_stop = stops.at(s); - uint rgb = current_stop.second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, flag, alpha); - if (s < stops.size()-1) - start += offset*(stops.at(s+1).first - stops.at(s).first); - flag = 1; - } - if (off_max > 1) { - start += (off_max - 1)*offset; - uint rgb = stops.at(stops.size()-1).second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, flag, alpha); - } - } - } else { - for (int i = 0; i < num; ++i) { - uchar flag = 0; - for (int s = 0; s < stops.size(); ++s) { - uint rgb = stops.at(s).second.rgba(); - int xpos = (int)(start.x()*factor_x); - int ypos = (int)(start.y()*factor_y); - writeTriangleLine(data, xpos, ypos, xoff, yoff, rgb, flag, alpha); - if (s < stops.size()-1) - start += offset*(stops.at(s+1).first - stops.at(s).first); - flag = 1; - } - } - } - triangles.resize((char *)data - triangles.constData()); - - QByteArray shader; - QPdf::ByteStream s(&shader); - s << "<<\n" - "/ShadingType 4\n" - "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") << - "/AntiAlias true\n" - "/BitsPerCoordinate 24\n" - "/BitsPerComponent 8\n" - "/BitsPerFlag 8\n" - "/Decode [" << xmin << xmax << ymin << ymax << (alpha ? "0 1]\n" : "0 1 0 1 0 1]\n") << - "/AntiAlias true\n" - "/Length " << triangles.length() << "\n" - ">>\n" - "stream\n" << triangles << "endstream\n" - "endobj\n"; - return shader; -} -#endif static void moveToHook(qfixed x, qfixed y, void *data) { @@ -1381,6 +1195,8 @@ void QPdfEngine::setBrush() bool specifyColor; int gStateObject = 0; int patternObject = d->addBrushPattern(d->stroker.matrix, &specifyColor, &gStateObject); + if (!patternObject && !specifyColor) + return; *d->currentPage << (patternObject ? "/PCSp cs " : "/CSp cs "); if (specifyColor) { @@ -2116,34 +1932,263 @@ int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height, return image; } -#ifdef USE_NATIVE_GRADIENTS -int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int *gStateObject) +struct QGradientBound { + qreal start; + qreal stop; + int function; + bool reverse; +}; + +int QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha) { - const QGradient *gradient = b.gradient(); - if (!gradient) - return 0; + QGradientStops stops = gradient->stops(); + if (stops.isEmpty()) { + stops << QGradientStop(0, Qt::black); + stops << QGradientStop(1, Qt::white); + } + if (stops.at(0).first > 0) + stops.prepend(QGradientStop(0, stops.at(0).second)); + if (stops.at(stops.size() - 1).first < 1) + stops.append(QGradientStop(1, stops.at(stops.size() - 1).second)); + + QVector functions; + for (int i = 0; i < stops.size() - 1; ++i) { + int f = addXrefEntry(-1); + QByteArray data; + QPdf::ByteStream s(&data); + s << "<<\n" + "/FunctionType 2\n" + "/Domain [0 1]\n" + "/N 1\n"; + if (alpha) { + s << "/C0 [" << stops.at(i).second.alphaF() << "]\n" + "/C1 [" << stops.at(i + 1).second.alphaF() << "]\n"; + } else { + s << "/C0 [" << stops.at(i).second.redF() << stops.at(i).second.greenF() << stops.at(i).second.blueF() << "]\n" + "/C1 [" << stops.at(i + 1).second.redF() << stops.at(i + 1).second.greenF() << stops.at(i + 1).second.blueF() << "]\n"; + } + s << ">>\n" + "endobj\n"; + write(data); + functions << f; + } + + QVector gradientBounds; - QTransform inv = matrix.inverted(); - QPointF page_rect[4] = { inv.map(QPointF(0, 0)), - inv.map(QPointF(width_, 0)), - inv.map(QPointF(0, height_)), - inv.map(QPointF(width_, height_)) }; + for (int step = from; step < to; ++step) { + if (reflect && step % 2) { + for (int i = stops.size() - 1; i > 0; --i) { + QGradientBound b; + b.start = step + 1 - qBound(0., stops.at(i).first, 1.); + b.stop = step + 1 - qBound(0., stops.at(i - 1).first, 1.); + b.function = functions.at(i - 1); + b.reverse = true; + gradientBounds << b; + } + } else { + for (int i = 0; i < stops.size() - 1; ++i) { + QGradientBound b; + b.start = step + qBound(0., stops.at(i).first, 1.); + b.stop = step + qBound(0., stops.at(i + 1).first, 1.); + b.function = functions.at(i); + b.reverse = false; + gradientBounds << b; + } + } + } - bool opaque = b.isOpaque(); + // normalize bounds to [0..1] + qreal bstart = gradientBounds.at(0).start; + qreal bend = gradientBounds.at(gradientBounds.size() - 1).stop; + qreal norm = 1./(bend - bstart); + for (int i = 0; i < gradientBounds.size(); ++i) { + gradientBounds[i].start = (gradientBounds[i].start - bstart)*norm; + gradientBounds[i].stop = (gradientBounds[i].stop - bstart)*norm; + } - QByteArray shader; - QByteArray alphaShader; - if (gradient->type() == QGradient::LinearGradient) { - const QLinearGradient *lg = static_cast(gradient); - shader = QPdf::generateLinearGradientShader(lg, page_rect); - if (!opaque) - alphaShader = QPdf::generateLinearGradientShader(lg, page_rect, true); + int function; + if (gradientBounds.size() > 1) { + function = addXrefEntry(-1); + QByteArray data; + QPdf::ByteStream s(&data); + s << "<<\n" + "/FunctionType 3\n" + "/Domain [0 1]\n" + "/Bounds ["; + for (int i = 1; i < gradientBounds.size(); ++i) + s << gradientBounds.at(i).start; + s << "]\n" + "/Encode ["; + for (int i = 0; i < gradientBounds.size(); ++i) + s << (gradientBounds.at(i).reverse ? "1 0 " : "0 1 "); + s << "]\n" + "/Functions ["; + for (int i = 0; i < gradientBounds.size(); ++i) + s << gradientBounds.at(i).function << "0 R "; + s << "]\n" + ">>\n"; + write(data); } else { - // ############# - return 0; + function = functions.at(0); + } + return function; +} + +int QPdfEnginePrivate::generateLinearGradientShader(const QLinearGradient *gradient, const QTransform &matrix, bool alpha) +{ + QPointF start = gradient->start(); + QPointF stop = gradient->finalStop(); + QPointF offset = stop - start; + Q_ASSERT(gradient->coordinateMode() == QGradient::LogicalMode); + + int from = 0; + int to = 1; + bool reflect = false; + switch (gradient->spread()) { + case QGradient::PadSpread: + break; + case QGradient::ReflectSpread: + reflect = true; + // fall through + case QGradient::RepeatSpread: { + // calculate required bounds + QRectF pageRect = m_pageLayout.fullRectPixels(resolution); + QTransform inv = matrix.inverted(); + QPointF page_rect[4] = { inv.map(pageRect.topLeft()), + inv.map(pageRect.topRight()), + inv.map(pageRect.bottomLeft()), + inv.map(pageRect.bottomRight()) }; + + qreal length = offset.x()*offset.x() + offset.y()*offset.y(); + + // find the max and min values in offset and orth direction that are needed to cover + // the whole page + from = INT_MAX; + to = INT_MIN; + for (int i = 0; i < 4; ++i) { + qreal off = ((page_rect[i].x() - start.x()) * offset.x() + (page_rect[i].y() - start.y()) * offset.y())/length; + from = qMin(from, qFloor(off)); + to = qMax(to, qCeil(off)); + } + + stop = start + to * offset; + start = start + from * offset;\ + break; + } + } + + int function = createShadingFunction(gradient, from, to, reflect, alpha); + + QByteArray shader; + QPdf::ByteStream s(&shader); + s << "<<\n" + "/ShadingType 2\n" + "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") << + "/AntiAlias true\n" + "/Coords [" << start.x() << start.y() << stop.x() << stop.y() << "]\n" + "/Extend [true true]\n" + "/Function " << function << "0 R\n" + ">>\n" + "endobj\n"; + int shaderObject = addXrefEntry(-1); + write(shader); + return shaderObject; +} + +int QPdfEnginePrivate::generateRadialGradientShader(const QRadialGradient *gradient, const QTransform &matrix, bool alpha) +{ + QPointF p1 = gradient->center(); + double r1 = gradient->centerRadius(); + QPointF p0 = gradient->focalPoint(); + double r0 = gradient->focalRadius(); + + Q_ASSERT(gradient->coordinateMode() == QGradient::LogicalMode); + + int from = 0; + int to = 1; + bool reflect = false; + switch (gradient->spread()) { + case QGradient::PadSpread: + break; + case QGradient::ReflectSpread: + reflect = true; + // fall through + case QGradient::RepeatSpread: { + Q_ASSERT(qFuzzyIsNull(r0)); // QPainter emulates if this is not 0 + + QRectF pageRect = m_pageLayout.fullRectPixels(resolution); + QTransform inv = matrix.inverted(); + QPointF page_rect[4] = { inv.map(pageRect.topLeft()), + inv.map(pageRect.topRight()), + inv.map(pageRect.bottomLeft()), + inv.map(pageRect.bottomRight()) }; + + // increase to until the whole page fits into it + bool done = false; + while (!done) { + QPointF center = QPointF(p0.x() + to*(p1.x() - p0.x()), p0.y() + to*(p1.y() - p0.y())); + double radius = r0 + to*(r1 - r0); + double r2 = radius*radius; + done = true; + for (int i = 0; i < 4; ++i) { + QPointF off = page_rect[i] - center; + if (off.x()*off.x() + off.y()*off.y() > r2) { + ++to; + done = false; + break; + } + } + } + p1 = QPointF(p0.x() + to*(p1.x() - p0.x()), p0.y() + to*(p1.y() - p0.y())); + r1 = r0 + to*(r1 - r0); + break; + } } + + int function = createShadingFunction(gradient, from, to, reflect, alpha); + + QByteArray shader; + QPdf::ByteStream s(&shader); + s << "<<\n" + "/ShadingType 3\n" + "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") << + "/AntiAlias true\n" + "/Domain [0 1]\n" + "/Coords [" << p0.x() << p0.y() << r0 << p1.x() << p1.y() << r1 << "]\n" + "/Extend [true true]\n" + "/Function " << function << "0 R\n" + ">>\n" + "endobj\n"; int shaderObject = addXrefEntry(-1); write(shader); + return shaderObject; +} + +int QPdfEnginePrivate::generateGradientShader(const QGradient *gradient, const QTransform &matrix, bool alpha) +{ + switch (gradient->type()) { + case QGradient::LinearGradient: + return generateLinearGradientShader(static_cast(gradient), matrix, alpha); + case QGradient::RadialGradient: + return generateRadialGradientShader(static_cast(gradient), matrix, alpha); + case QGradient::ConicalGradient: + default: + qWarning() << "Implement me!"; + } + return 0; +} + +int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QTransform &matrix, int *gStateObject) +{ + const QGradient *gradient = b.gradient(); + + if (!gradient || gradient->coordinateMode() != QGradient::LogicalMode) + return 0; + + QRectF pageRect = m_pageLayout.fullRectPixels(resolution); + + QTransform m = b.transform() * matrix; + int shaderObject = generateGradientShader(gradient, m); QByteArray str; QPdf::ByteStream s(&str); @@ -2152,12 +2197,12 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int "/PatternType 2\n" "/Shading " << shaderObject << "0 R\n" "/Matrix [" - << matrix.m11() - << matrix.m12() - << matrix.m21() - << matrix.m22() - << matrix.dx() - << matrix.dy() << "]\n"; + << m.m11() + << m.m12() + << m.m21() + << m.m22() + << m.dx() + << m.dy() << "]\n"; s << ">>\n" "endobj\n"; @@ -2165,7 +2210,7 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int write(str); currentPage->patterns.append(patternObj); - if (!opaque) { + if (!b.isOpaque()) { bool ca = true; QGradientStops stops = gradient->stops(); int a = stops.at(0).second.alpha(); @@ -2178,8 +2223,7 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int if (ca) { *gStateObject = addConstantAlphaObject(stops.at(0).second.alpha()); } else { - int alphaShaderObject = addXrefEntry(-1); - write(alphaShader); + int alphaShaderObject = generateGradientShader(gradient, m, true); QByteArray content; QPdf::ByteStream c(&content); @@ -2190,7 +2234,7 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int f << "<<\n" "/Type /XObject\n" "/Subtype /Form\n" - "/BBox [0 0 " << width_ << height_ << "]\n" + "/BBox [0 0 " << pageRect.width() << pageRect.height() << "]\n" "/Group <>\n" "/Resources <<\n" "/Shading << /Shader" << alphaShaderObject << alphaShaderObject << "0 R >>\n" @@ -2214,7 +2258,6 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QMatrix &matrix, int return patternObj; } -#endif int QPdfEnginePrivate::addConstantAlphaObject(int brushAlpha, int penAlpha) { @@ -2236,6 +2279,7 @@ int QPdfEnginePrivate::addConstantAlphaObject(int brushAlpha, int penAlpha) return object; } + int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor, int *gStateObject) { int paintType = 2; // Uncolored tiling @@ -2251,13 +2295,9 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor, //qDebug() << brushOrigin << matrix; Qt::BrushStyle style = brush.style(); - if (style == Qt::LinearGradientPattern) {// && style <= Qt::ConicalGradientPattern) { -#ifdef USE_NATIVE_GRADIENTS + if (style == Qt::LinearGradientPattern || style == Qt::RadialGradientPattern) {// && style <= Qt::ConicalGradientPattern) { *specifyColor = false; - return gradientBrush(b, matrix, gStateObject); -#else - return 0; -#endif + return gradientBrush(brush, matrix, gStateObject); } if ((!brush.isOpaque() && brush.style() < Qt::LinearGradientPattern) || opacity != 1.0) diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h index e7ff09cd3b..94e74f30b9 100644 --- a/src/gui/painting/qpdf_p.h +++ b/src/gui/painting/qpdf_p.h @@ -58,8 +58,6 @@ #include "private/qfontsubset_p.h" #include "qpagelayout.h" -// #define USE_NATIVE_GRADIENTS - QT_BEGIN_NAMESPACE const char *qt_real_to_string(qreal val, char *buf); @@ -116,9 +114,6 @@ namespace QPdf { QByteArray generateMatrix(const QTransform &matrix); QByteArray generateDashes(const QPen &pen); QByteArray patternForBrush(const QBrush &b); -#ifdef USE_NATIVE_GRADIENTS - QByteArray generateLinearGradientShader(const QLinearGradient *lg, const QPointF *page_rect, bool alpha = false); -#endif struct Stroker { Stroker(); @@ -276,9 +271,11 @@ public: QPageLayout m_pageLayout; private: -#ifdef USE_NATIVE_GRADIENTS - int gradientBrush(const QBrush &b, const QMatrix &matrix, int *gStateObject); -#endif + int gradientBrush(const QBrush &b, const QTransform &matrix, int *gStateObject); + int generateGradientShader(const QGradient *gradient, const QTransform &matrix, bool alpha = false); + int generateLinearGradientShader(const QLinearGradient *lg, const QTransform &matrix, bool alpha); + int generateRadialGradientShader(const QRadialGradient *gradient, const QTransform &matrix, bool alpha); + int createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha); void writeInfo(); void writePageRoot(); -- cgit v1.2.3 From 29380121efad2355a69cb3f8110bf193baa312b4 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 13 Apr 2015 11:28:33 +0200 Subject: Fix RGB30 painting tests Some tests were failing because the color was not read correctly from a QImage. To make it possibly to read more accurate colors a pixel accessor returing QColor has been added. Some tests also had the wrong order of arguments, confusing dest and src formats. This has been corrected, so they test what they claim to test. A test for RGB30 linear gradients is also added. Change-Id: Ic623ae1b8e0bf7383056b641c6e8230a1d7dd0dd Reviewed-by: Gunnar Sletta --- src/gui/painting/qdrawhelper.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index b6f06135cd..b2992a138e 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -4698,10 +4698,8 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in } ++spans; } - if (!alphaSpans) { + if (!alphaSpans) op.destFetch = 0; - op.destFetch64 = 0; - } } } } @@ -4795,10 +4793,9 @@ void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData) int length = spans->len; while (length) { int l = qMin(buffer_size, length); - QRgba64 *dest = op.destFetch64 ? op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l) : buffer; + QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l); op.funcSolid64(dest, l, color, spans->coverage); - if (op.destStore64) - op.destStore64(data->rasterBuffer, x, spans->y, dest, l); + op.destStore64(data->rasterBuffer, x, spans->y, dest, l); length -= l; x += l; } @@ -4987,7 +4984,7 @@ public: bool isSupported() const { - return op.srcFetch64 && op.func64; + return op.srcFetch64 && op.func64 && op.destFetch64 && op.destStore64; } const QRgba64 *fetch(int x, int y, int len) @@ -5108,10 +5105,9 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi while (length) { int l = qMin(buffer_size, length); const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l); - QRgba64 *dest = op.destFetch64 ? op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l) : buffer; + QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l); op.func64(dest, src, l, coverage); - if (op.destStore64) - op.destStore64(data->rasterBuffer, x, spans->y, dest, l); + op.destStore64(data->rasterBuffer, x, spans->y, dest, l); x += l; sx += l; length -= l; @@ -5353,10 +5349,9 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD if (buffer_size < l) l = buffer_size; const QRgba64 *src = op.srcFetch64(src_buffer, &op, data, sy, sx, l); - QRgba64 *dest = op.destFetch64 ? op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l) : buffer; + QRgba64 *dest = op.destFetch64(buffer, data->rasterBuffer, x, spans->y, l); op.func64(dest, src, l, coverage); - if (op.destStore64) - op.destStore64(data->rasterBuffer, x, spans->y, dest, l); + op.destStore64(data->rasterBuffer, x, spans->y, dest, l); x += l; sx += l; length -= l; -- cgit v1.2.3 From 5c7d2d1d6772b1d7e808aa37659ce5654f0862da Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 10 Apr 2015 15:34:23 +0200 Subject: Add support for more composition modes in rgb64 rendering Change-Id: I3bacecbabdf2d7b2de1acd86ab9383e69924a390 Reviewed-by: Gunnar Sletta --- src/gui/painting/qdrawhelper.cpp | 271 ++++++++++++++++++++++++++++++++++++++- src/gui/painting/qrgba64_p.h | 20 +++ 2 files changed, 287 insertions(+), 4 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index b2992a138e..2dab2ba859 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -3029,6 +3029,23 @@ void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, ui } } +void QT_FASTCALL comp_func_solid_SourceIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(color, dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + color = multiplyAlpha65535(color, ca); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(color, d.alpha(), d, cia); + } + } +} + void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { PRELOAD_INIT2(dest, src) @@ -3048,6 +3065,23 @@ void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DE } } +void QT_FASTCALL comp_func_SourceIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(src[i], dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha65535(src[i], ca); + dest[i] = interpolate65535(s, d.alpha(), d, cia); + } + } +} + /* result = d * sa dest = d * sa * ca + d * cia @@ -3066,6 +3100,17 @@ void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint colo } } +void QT_FASTCALL comp_func_solid_DestinationIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + uint a = color.alpha(); + uint ca64k = const_alpha * 257; + if (const_alpha != 255) + a = qt_div_65535(a * ca64k) + 65535 - ca64k; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], a); + } +} + void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { PRELOAD_INIT2(dest, src) @@ -3084,6 +3129,22 @@ void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint } } +void QT_FASTCALL comp_func_DestinationIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], src[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + uint a = qt_div_65535(src[i].alpha() * ca) + cia; + dest[i] = multiplyAlpha65535(dest[i], a); + } + } +} + /* result = s * dia dest = s * dia * ca + d * cia @@ -3108,6 +3169,23 @@ void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, u } } +void QT_FASTCALL comp_func_solid_SourceOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(color, 65535 - dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + color = multiplyAlpha65535(color, ca); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(color, 65535 - d.alpha(), d, cia); + } + } +} + void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { PRELOAD_INIT2(dest, src) @@ -3127,6 +3205,23 @@ void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_D } } +void QT_FASTCALL comp_func_SourceOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(src[i], 65535 - dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha65535(src[i], ca); + dest[i] = interpolate65535(s, 65535 - d.alpha(), d, cia); + } + } +} + /* result = d * sia dest = d * sia * ca + d * cia @@ -3144,6 +3239,17 @@ void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint col } } +void QT_FASTCALL comp_func_solid_DestinationOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + uint a = 65535 - color.alpha(); + uint ca64k = const_alpha * 257; + if (const_alpha != 255) + a = qt_div_65535(a * ca64k) + 65535 - ca64k; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], a); + } +} + void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { PRELOAD_INIT2(dest, src) @@ -3162,6 +3268,22 @@ void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint } } +void QT_FASTCALL comp_func_DestinationOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], 65535 - src[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + uint a = qt_div_65535((65535 - src[i].alpha()) * ca) + cia; + dest[i] = multiplyAlpha65535(dest[i], a); + } + } +} + /* result = s*da + d*sia dest = s*da*ca + d*sia*ca + d *cia @@ -3181,6 +3303,16 @@ void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, } } +void QT_FASTCALL comp_func_solid_SourceAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + uint sia = 65535 - color.alpha(); + for (int i = 0; i < length; ++i) { + dest[i] = interpolate65535(color, dest[i].alpha(), dest[i], sia); + } +} + void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { PRELOAD_INIT2(dest, src) @@ -3201,6 +3333,23 @@ void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_ } } +void QT_FASTCALL comp_func_SourceAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 s = src[i]; + QRgba64 d = dest[i]; + dest[i] = interpolate65535(s, d.alpha(), d, 65535 - s.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + QRgba64 d = dest[i]; + dest[i] = interpolate65535(s, d.alpha(), d, 65535 - s.alpha()); + } + } +} + /* result = d*sa + s*dia dest = d*sa*ca + s*dia*ca + d *cia @@ -3221,6 +3370,19 @@ void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint co } } +void QT_FASTCALL comp_func_solid_DestinationAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + uint a = color.alpha(); + if (const_alpha != 255) { + color = multiplyAlpha255(color, const_alpha); + a = color.alpha() + 65535 - (const_alpha * 257); + } + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(d, a, color, 65535 - d.alpha()); + } +} + void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { PRELOAD_INIT2(dest, src) @@ -3243,6 +3405,26 @@ void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uin } } +void QT_FASTCALL comp_func_DestinationAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 s = src[i]; + QRgba64 d = dest[i]; + dest[i] = interpolate65535(d, s.alpha(), s, 65535 - d.alpha()); + } + } else { + int ca = const_alpha * 257; + int cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + QRgba64 s = multiplyAlpha65535(src[i], ca); + QRgba64 d = dest[i]; + uint a = s.alpha() + cia; + dest[i] = interpolate65535(d, a, s, 65535 - d.alpha()); + } + } +} + /* result = d*sia + s*dia dest = d*sia*ca + s*dia*ca + d *cia @@ -3263,6 +3445,17 @@ void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint co } } +void QT_FASTCALL comp_func_solid_XOR_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + uint sia = 65535 - color.alpha(); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(color, 65535 - d.alpha(), d, sia); + } +} + void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) { PRELOAD_INIT2(dest, src) @@ -3283,6 +3476,23 @@ void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RE } } +void QT_FASTCALL comp_func_XOR_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = src[i]; + dest[i] = interpolate65535(s, 65535 - d.alpha(), d, 65535 - s.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + dest[i] = interpolate65535(s, 65535 - d.alpha(), d, 65535 - s.alpha()); + } + } +} + struct QFullCoverage { inline void store(uint *dest, const uint src) const { @@ -3330,6 +3540,17 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int } } +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl_rgb64(QRgba64 *dest, int length, QRgba64 color, const T &coverage) +{ + QRgba64 s = color; + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + d = comp_func_Plus_one_pixel(d, s); + coverage.store(&dest[i], d); + } +} + void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha) { if (const_alpha == 255) @@ -3338,6 +3559,20 @@ void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint c comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha)); } +void QT_FASTCALL comp_func_solid_Plus_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = addWithSaturation(dest[i], color); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = addWithSaturation(dest[i], color); + dest[i] = interpolate255(d, const_alpha, dest[i], 255 - const_alpha); + } + } +} + template Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) { @@ -3361,6 +3596,20 @@ void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_R comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha)); } +void QT_FASTCALL comp_func_Plus_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = addWithSaturation(dest[i], src[i]); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = addWithSaturation(dest[i], src[i]); + dest[i] = interpolate255(d, const_alpha, dest[i], 255 - const_alpha); + } + } +} + /* Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) */ @@ -4552,8 +4801,15 @@ static CompositionFunctionSolid64 functionForModeSolid64_C[] = { comp_func_solid_Clear_rgb64, comp_func_solid_Source_rgb64, comp_func_solid_Destination_rgb64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, + comp_func_solid_SourceIn_rgb64, + comp_func_solid_DestinationIn_rgb64, + comp_func_solid_SourceOut_rgb64, + comp_func_solid_DestinationOut_rgb64, + comp_func_solid_SourceAtop_rgb64, + comp_func_solid_DestinationAtop_rgb64, + comp_func_solid_XOR_rgb64, + comp_func_solid_Plus_rgb64, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 @@ -4609,8 +4865,15 @@ static CompositionFunction64 functionForMode64_C[] = { comp_func_Clear_rgb64, comp_func_Source_rgb64, comp_func_Destination_rgb64, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, + comp_func_SourceIn_rgb64, + comp_func_DestinationIn_rgb64, + comp_func_SourceOut_rgb64, + comp_func_DestinationOut_rgb64, + comp_func_SourceAtop_rgb64, + comp_func_DestinationAtop_rgb64, + comp_func_XOR_rgb64, + comp_func_Plus_rgb64, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 diff --git a/src/gui/painting/qrgba64_p.h b/src/gui/painting/qrgba64_p.h index a1452af8d9..0301c2a7de 100644 --- a/src/gui/painting/qrgba64_p.h +++ b/src/gui/painting/qrgba64_p.h @@ -78,6 +78,26 @@ inline QRgba64 interpolate255(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2) return QRgba64::fromRgba64(multiplyAlpha255(x, alpha1) + multiplyAlpha255(y, alpha2)); } +inline QRgba64 interpolate65535(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2) +{ + return QRgba64::fromRgba64(multiplyAlpha65535(x, alpha1) + multiplyAlpha65535(y, alpha2)); +} + +inline QRgba64 addWithSaturation(QRgba64 a, QRgba64 b) +{ +#if defined(__SSE2__) && defined(Q_PROCESSOR_X86_64) + __m128i va = _mm_cvtsi64_si128((quint64)a); + __m128i vb = _mm_cvtsi64_si128((quint64)b); + va = _mm_adds_epu16(va, vb); + return QRgba64::fromRgba64(_mm_cvtsi128_si64(va)); +#else + return QRgba64::fromRgba64(qMin(a.red() + b.red(), 65535), + qMin(a.green() + b.green(), 65535), + qMin(a.blue() + b.blue(), 65535), + qMin(a.alpha() + b.alpha(), 65535)); +#endif +} + QT_END_NAMESPACE #endif // QRGBA64_P_H -- cgit v1.2.3 From ac659cd203bc43c472c58191cba3fe4f96247dfa Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 9 Apr 2015 10:49:27 +0200 Subject: Extend high color rendering to image rendering A previous commit added 16-bit per color-channel precision to solids and linear gradients. This patch extends that to include texture data. To support that pixellayouts now have a method to convert to RGBA64. Change-Id: I661ae91bd7038085787003608a0af4add057e478 Reviewed-by: Gunnar Sletta --- src/gui/painting/qdrawhelper.cpp | 1133 +++++++++++++++++++++++++++++++++++--- src/gui/painting/qdrawhelper_p.h | 3 + src/gui/painting/qrgba64_p.h | 33 +- 3 files changed, 1082 insertions(+), 87 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 2dab2ba859..aad904e8fc 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -184,6 +184,36 @@ static const uint *QT_FASTCALL convertToRGB32(uint *buffer, const uint *src, int return buffer; } +template +static const QRgba64 *QT_FASTCALL convertToRGB64(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + Q_CONSTEXPR uint redMask = ((1 << redWidth()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth()) - 1); + + Q_CONSTEXPR uchar redLeftShift = 8 - redWidth(); + Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth(); + Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth(); + + Q_CONSTEXPR uchar redRightShift = 2 * redWidth() - 8; + Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth() - 8; + Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth() - 8; + + for (int i = 0; i < count; ++i) { + uint red = (src[i] >> redShift()) & redMask; + uint green = (src[i] >> greenShift()) & greenMask; + uint blue = (src[i] >> blueShift()) & blueMask; + + red = ((red << redLeftShift) | (red >> redRightShift)) << 16; + green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8; + blue = (blue << blueLeftShift) | (blue >> blueRightShift); + buffer[i] = QRgba64::fromRgba(red, green, blue, 255); + } + + return buffer; +} + template static const uint *QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) @@ -219,6 +249,41 @@ static const uint *QT_FASTCALL convertARGBPMToARGB32PM(uint *buffer, const uint return buffer; } +template +static const QRgba64 *QT_FASTCALL convertARGBPMToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + Q_CONSTEXPR uint alphaMask = ((1 << alphaWidth()) - 1); + Q_CONSTEXPR uint redMask = ((1 << redWidth()) - 1); + Q_CONSTEXPR uint greenMask = ((1 << greenWidth()) - 1); + Q_CONSTEXPR uint blueMask = ((1 << blueWidth()) - 1); + + Q_CONSTEXPR uchar alphaLeftShift = 8 - alphaWidth(); + Q_CONSTEXPR uchar redLeftShift = 8 - redWidth(); + Q_CONSTEXPR uchar greenLeftShift = 8 - greenWidth(); + Q_CONSTEXPR uchar blueLeftShift = 8 - blueWidth(); + + Q_CONSTEXPR uchar alphaRightShift = 2 * alphaWidth() - 8; + Q_CONSTEXPR uchar redRightShift = 2 * redWidth() - 8; + Q_CONSTEXPR uchar greenRightShift = 2 * greenWidth() - 8; + Q_CONSTEXPR uchar blueRightShift = 2 * blueWidth() - 8; + + for (int i = 0; i < count; ++i) { + uint alpha = (src[i] >> alphaShift()) & alphaMask; + uint red = (src[i] >> redShift()) & redMask; + uint green = (src[i] >> greenShift()) & greenMask; + uint blue = (src[i] >> blueShift()) & blueMask; + + alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift); + red = qMin(alpha, (red << redLeftShift) | (red >> redRightShift)); + green = qMin(alpha, (green << greenLeftShift) | (green >> greenRightShift)); + blue = qMin(alpha, (blue << blueLeftShift) | (blue >> blueRightShift)); + buffer[i] = QRgba64::fromRgba(red, green, blue, alpha); + } + + return buffer; +} + template static const uint *QT_FASTCALL convertRGBFromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) @@ -321,7 +386,8 @@ template Q_DECL_CONSTEXPR static inline QPixelLayout pixe false, bitsPerPixel(), convertToRGB32, convertRGBFromARGB32PM, - convertRGBFromRGB32 + convertRGBFromRGB32, + convertToRGB64 }; } @@ -335,7 +401,8 @@ template Q_DECL_CONSTEXPR static inline QPixelLayout pixe true, bitsPerPixel(), convertARGBPMToARGB32PM, convertARGBPMFromARGB32PM, - convertARGBPMFromRGB32 + convertARGBPMFromRGB32, + convertARGBPMToARGB64PM }; } @@ -350,6 +417,14 @@ static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint return buffer; } +static const QRgba64 *QT_FASTCALL convertIndexedToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *clut) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(clut[src[i]]).premultiplied(); + return buffer; +} + static const uint *QT_FASTCALL convertPassThrough(uint *, const uint *src, int, const QPixelLayout *, const QRgb *) { @@ -392,6 +467,22 @@ static const uint *QT_FASTCALL convertGrayscale8ToRGB32(uint *buffer, const uint return buffer; } +static const QRgba64 *QT_FASTCALL convertAlpha8ToRGB64(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromRgba(0, 0, 0, src[i]); + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertGrayscale8ToRGB64(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromRgba(src[i], src[i], src[i], 255); + return buffer; +} + static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { @@ -408,6 +499,111 @@ static const uint *QT_FASTCALL convertRGBA8888PMFromARGB32PM(uint *buffer, const return buffer; } +#ifdef __SSE2__ +template +static inline void qConvertARGB32PMToARGB64PM_sse2(QRgba64 *buffer, const uint *src, int count) +{ + const __m128i amask = _mm_set1_epi32(0xff000000); + int i = 0; + if (((uintptr_t)buffer & 0xf) && count > 0) { + uint s = *src++; + if (RGBA) + s = RGBA2ARGB(s); + *buffer++ = QRgba64::fromArgb32(s); + i++; + } + for (; i < count-3; i += 4) { + __m128i vs = _mm_loadu_si128((const __m128i*)src); + if (maskAlpha) + vs = _mm_or_si128(vs, amask); + src += 4; + __m128i v1 = _mm_unpacklo_epi8(vs, vs); + __m128i v2 = _mm_unpackhi_epi8(vs, vs); + if (!RGBA) { + v1 = _mm_shufflelo_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2)); + v2 = _mm_shufflelo_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2)); + v1 = _mm_shufflehi_epi16(v1, _MM_SHUFFLE(3, 0, 1, 2)); + v2 = _mm_shufflehi_epi16(v2, _MM_SHUFFLE(3, 0, 1, 2)); + } + _mm_store_si128((__m128i*)(buffer), v1); + buffer += 2; + _mm_store_si128((__m128i*)(buffer), v2); + buffer += 2; + } + + for (; i < count; ++i) { + uint s = *src++; + if (RGBA) + s = RGBA2ARGB(s); + *buffer++ = QRgba64::fromArgb32(s); + } +} +#endif + +static const QRgba64 *QT_FASTCALL convertRGB32ToRGB64(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(0xff000000 | src[i]); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertARGB32ToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2(buffer, src, count); + for (int i = 0; i < count; ++i) + buffer[i] = buffer[i].premultiplied(); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied(); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertARGB32PMToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(src[i]); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertRGBA8888ToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2(buffer, src, count); + for (int i = 0; i < count; ++i) + buffer[i] = buffer[i].premultiplied(); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])).premultiplied(); +#endif + return buffer; +} + +static const QRgba64 *QT_FASTCALL convertRGBA8888PMToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertARGB32PMToARGB64PM_sse2(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = QRgba64::fromArgb32(RGBA2ARGB(src[i])); +#endif + return buffer; +} + static const uint *QT_FASTCALL convertRGBA8888FromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) { @@ -441,6 +637,60 @@ static const uint *QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, const ui return buffer; } +#ifdef __SSE2__ +template +static inline void qConvertA2RGB30PMToARGB64PM_sse2(QRgba64 *buffer, const uint *src, int count) +{ + const __m128i rmask = _mm_set1_epi32(0x3ff00000); + const __m128i gmask = _mm_set1_epi32(0x000ffc00); + const __m128i bmask = _mm_set1_epi32(0x000003ff); + const __m128i afactor = _mm_set1_epi16(0x5555); + int i = 0; + if (((uintptr_t)buffer & 0xf) && count > 0) { + *buffer++ = qConvertA2rgb30ToRgb64(*src++); + i++; + } + for (; i < count-3; i += 4) { + __m128i vs = _mm_loadu_si128((const __m128i*)src); + src += 4; + __m128i va = _mm_srli_epi32(vs, 30); + __m128i vr = _mm_and_si128(vs, rmask); + __m128i vb = _mm_and_si128(vs, bmask); + __m128i vg = _mm_and_si128(vs, gmask); + va = _mm_mullo_epi16(va, afactor); + vr = _mm_or_si128(_mm_srli_epi32(vr, 14), _mm_srli_epi32(vr, 24)); + vg = _mm_or_si128(_mm_srli_epi32(vg, 4), _mm_srli_epi32(vg, 14)); + vb = _mm_or_si128(_mm_slli_epi32(vb, 6), _mm_srli_epi32(vb, 4)); + __m128i vrb; + if (PixelOrder == PixelOrderRGB) + vrb = _mm_or_si128(vr, _mm_slli_si128(vb, 2)); + else + vrb = _mm_or_si128(vb, _mm_slli_si128(vr, 2)); + __m128i vga = _mm_or_si128(vg, _mm_slli_si128(va, 2)); + _mm_store_si128((__m128i*)(buffer), _mm_unpacklo_epi16(vrb, vga)); + buffer += 2; + _mm_store_si128((__m128i*)(buffer), _mm_unpackhi_epi16(vrb, vga)); + buffer += 2; + } + + for (; i < count; ++i) + *buffer++ = qConvertA2rgb30ToRgb64(*src++); +} +#endif + +template +static const QRgba64 *QT_FASTCALL convertA2RGB30PMToARGB64PM(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *, const QRgb *) +{ +#ifdef __SSE2__ + qConvertA2RGB30PMToARGB64PM_sse2(buffer, src, count); +#else + for (int i = 0; i < count; ++i) + buffer[i] = qConvertA2rgb30ToRgb64(src[i]); +#endif + return buffer; +} + template static const uint *QT_FASTCALL convertA2RGB30PMFromARGB32PM(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *) @@ -602,15 +852,15 @@ inline void QT_FASTCALL storePixels(uchar *dest, const uint // convertFromArgb32() assumes that no color channel is more than 8 bits. // QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits. QPixelLayout qPixelLayouts[QImage::NImageFormats] = { - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPPNone, 0, 0, 0 }, // Format_Invalid - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0, 0 }, // Format_Mono - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0, 0 }, // Format_MonoLSB - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0, 0 }, // Format_Indexed8 + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPPNone, 0, 0, 0, 0 }, // Format_Invalid + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Mono + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_MonoLSB + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0, 0, convertIndexedToARGB64PM }, // Format_Indexed8 // Technically using convertPassThrough to convert from ARGB32PM to RGB32 is wrong, // but everywhere this generic conversion would be wrong is currently overloaded. - { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough }, // Format_RGB32 - { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, convertPassThrough }, // Format_ARGB32 - { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough }, // Format_ARGB32_Premultiplied + { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough, convertRGB32ToRGB64 }, // Format_RGB32 + { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM, convertPassThrough, convertARGB32ToARGB64PM }, // Format_ARGB32 + { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough, convertPassThrough, convertARGB32PMToARGB64PM }, // Format_ARGB32_Premultiplied #ifdef Q_COMPILER_CONSTEXPR pixelLayoutRGB(), pixelLayoutARGBPM(), @@ -625,55 +875,73 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = { { 5, 11, 6, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertRGBFromARGB32PM, - convertRGBFromRGB32}, + convertRGBFromRGB32, + convertToRGB64, + }, { 5, 19, 6, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertARGBPMToARGB32PM, convertARGBPMFromARGB32PM, - convertARGBPMFromRGB32}, + convertARGBPMFromRGB32, + convertARGBPMToARGB64PM, + }, { 6, 12, 6, 6, 6, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertRGBFromARGB32PM, - convertRGBFromRGB32}, + convertRGBFromRGB32, + convertToRGB64, + }, { 6, 12, 6, 6, 6, 0, 6, 18, true, QPixelLayout::BPP24, convertARGBPMToARGB32PM, convertARGBPMFromARGB32PM, - convertARGBPMFromRGB32}, + convertARGBPMFromRGB32, + convertARGBPMToARGB64PM, + }, { 5, 10, 5, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertRGBFromARGB32PM, - convertRGBFromRGB32 }, + convertRGBFromRGB32, + convertToRGB64, + }, { 5, 18, 5, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertARGBPMToARGB32PM, convertARGBPMFromARGB32PM, - convertARGBPMFromRGB32}, + convertARGBPMFromRGB32, + convertARGBPMToARGB64PM, + }, { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertRGBFromARGB32PM, - convertRGBFromRGB32}, + convertRGBFromRGB32, + convertToRGB64, + }, { 4, 8, 4, 4, 4, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertRGBFromARGB32PM, - convertRGBFromRGB32}, + convertRGBFromRGB32, + convertToRGB64, + }, { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16, convertARGBPMToARGB32PM, convertARGBPMFromARGB32PM, - convertARGBPMFromRGB32}, + convertARGBPMFromRGB32, + convertARGBPMToARGB64PM, + }, #endif #if Q_BYTE_ORDER == Q_BIG_ENDIAN - { 8, 24, 8, 16, 8, 8, 0, 0, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBX8888 - { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBA8888 - { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32}, // Format_RGBA8888_Premultiplied + { 8, 24, 8, 16, 8, 8, 0, 0, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBX8888 + { 8, 24, 8, 16, 8, 8, 8, 0, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32, convertRGBA8888ToARGB64PM }, // Format_RGBA8888 + { 8, 24, 8, 16, 8, 8, 8, 0, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM}, // Format_RGBA8888_Premultiplied #else - { 8, 0, 8, 8, 8, 16, 0, 24, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBX8888 - { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBA8888 (ABGR32) - { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32 }, // Format_RGBA8888_Premultiplied + { 8, 0, 8, 8, 8, 16, 0, 24, false, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBXFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBX8888 + { 8, 0, 8, 8, 8, 16, 8, 24, false, QPixelLayout::BPP32, convertRGBA8888ToARGB32PM, convertRGBA8888FromARGB32PM, convertRGBXFromRGB32, convertRGBA8888ToARGB64PM }, // Format_RGBA8888 (ABGR32) + { 8, 0, 8, 8, 8, 16, 8, 24, true, QPixelLayout::BPP32, convertRGBA8888PMToARGB32PM, convertRGBA8888PMFromARGB32PM, convertRGBXFromRGB32, convertRGBA8888PMToARGB64PM }, // Format_RGBA8888_Premultiplied #endif - { 10, 20, 10, 10, 10, 0, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM, convertRGB30FromARGB32PM, convertRGB30FromRGB32 }, // Format_BGR30 - { 10, 20, 10, 10, 10, 0, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM, convertA2RGB30PMFromARGB32PM, convertRGB30FromRGB32 }, // Format_A2BGR30_Premultiplied - { 10, 0, 10, 10, 10, 20, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM, convertRGB30FromARGB32PM, convertRGB30FromRGB32 }, // Format_RGB30 - { 10, 0, 10, 10, 10, 20, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM, convertA2RGB30PMFromARGB32PM, convertRGB30FromRGB32 }, // Format_A2RGB30_Premultiplied - { 0, 0, 0, 0, 0, 0, 8, 0, false, QPixelLayout::BPP8, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0 }, // Format_Alpha8 - { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32 } // Format_Grayscale8 + { 10, 20, 10, 10, 10, 0, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM, convertRGB30FromARGB32PM, convertRGB30FromRGB32, convertA2RGB30PMToARGB64PM }, // Format_BGR30 + { 10, 20, 10, 10, 10, 0, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM, convertA2RGB30PMFromARGB32PM, convertRGB30FromRGB32, convertA2RGB30PMToARGB64PM }, // Format_A2BGR30_Premultiplied + { 10, 0, 10, 10, 10, 20, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM, convertRGB30FromARGB32PM, convertRGB30FromRGB32, convertA2RGB30PMToARGB64PM }, // Format_RGB30 + { 10, 0, 10, 10, 10, 20, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM, convertA2RGB30PMFromARGB32PM, convertRGB30FromRGB32, convertA2RGB30PMToARGB64PM }, // Format_A2RGB30_Premultiplied + { 0, 0, 0, 0, 0, 0, 8, 0, false, QPixelLayout::BPP8, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0, convertAlpha8ToRGB64 }, // Format_Alpha8 + { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32, convertGrayscale8ToRGB64 } // Format_Grayscale8 }; FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = { @@ -764,29 +1032,14 @@ static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBu const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; uint buffer32[buffer_size]; const uint *ptr = qFetchPixels[layout->bpp](buffer32, rasterBuffer->scanLine(y), x, length); - ptr = const_cast(layout->convertToARGB32PM(buffer32, ptr, length, layout, 0)); - - for (int i = 0; i < length; ++i) { - buffer[i] = QRgba64::fromArgb32(ptr[i]); - } - return buffer; -} - -static QRgba64 *QT_FASTCALL destFetch64ARGB32(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) -{ - const uint *src = ((const uint *)rasterBuffer->scanLine(y)) + x; - for (int i = 0; i < length; ++i) - buffer[i] = QRgba64::fromArgb32(src[i]).premultiplied(); - return buffer; + return const_cast(layout->convertToARGB64PM(buffer, ptr, length, layout, 0)); } -template -static QRgba64 *QT_FASTCALL destFetch64RGB30(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) +static QRgba64 *QT_FASTCALL destFetch64uint32(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length) { + const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format]; const uint *src = ((const uint *)rasterBuffer->scanLine(y)) + x; - for (int i = 0; i < length; ++i) - buffer[i] = qConvertA2rgb30ToRgb64(src[i]); - return buffer; + return const_cast(layout->convertToARGB64PM(buffer, src, length, layout, 0)); } static DestFetchProc destFetchProc[QImage::NImageFormats] = @@ -824,9 +1077,9 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] = destFetch64, // Format_Mono, destFetch64, // Format_MonoLSB 0, // Format_Indexed8 - destFetch64, // Format_RGB32 - destFetch64ARGB32, // Format_ARGB32, - destFetch64, // Format_ARGB32_Premultiplied + destFetch64uint32, // Format_RGB32 + destFetch64uint32, // Format_ARGB32, + destFetch64uint32, // Format_ARGB32_Premultiplied destFetch64, // Format_RGB16 destFetch64, // Format_ARGB8565_Premultiplied destFetch64, // Format_RGB666 @@ -836,13 +1089,13 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] = destFetch64, // Format_RGB888 destFetch64, // Format_RGB444 destFetch64, // Format_ARGB4444_Premultiplied - destFetch64, // Format_RGBX8888 - destFetch64, // Format_RGBA8888 - destFetch64, // Format_RGBA8888_Premultiplied - destFetch64RGB30, // Format_BGR30 - destFetch64RGB30, // Format_A2BGR30_Premultiplied - destFetch64RGB30, // Format_RGB30 - destFetch64RGB30, // Format_A2RGB30_Premultiplied + destFetch64uint32, // Format_RGBX8888 + destFetch64uint32, // Format_RGBA8888 + destFetch64uint32, // Format_RGBA8888_Premultiplied + destFetch64uint32, // Format_BGR30 + destFetch64uint32, // Format_A2BGR30_Premultiplied + destFetch64uint32, // Format_RGB30 + destFetch64uint32, // Format_A2RGB30_Premultiplied destFetch64, // Format_Alpha8 destFetch64, // Format_Grayscale8 }; @@ -991,6 +1244,40 @@ static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, c } } +#ifdef __SSE2__ +template +static inline void qConvertARGB64PMToA2RGB30PM_sse2(uint *dest, const QRgba64 *buffer, int count) +{ + const __m128i gmask = _mm_set1_epi32(0x000ffc00); + const __m128i cmask = _mm_set1_epi32(0x000003ff); + int i = 0; + __m128i vr, vg, vb, va; + for (; i < count-1; i += 2) { + __m128i vs = _mm_loadu_si128((const __m128i*)buffer); + buffer += 2; + vr = _mm_srli_epi64(vs, 6); + vg = _mm_srli_epi64(vs, 16 + 6 - 10); + vb = _mm_srli_epi64(vs, 32 + 6); + vr = _mm_and_si128(vr, cmask); + vg = _mm_and_si128(vg, gmask); + vb = _mm_and_si128(vb, cmask); + va = _mm_srli_epi64(vs, 48 + 14); + if (PixelOrder == PixelOrderRGB) + vr = _mm_slli_epi32(vr, 20); + else + vb = _mm_slli_epi32(vb, 20); + va = _mm_slli_epi32(va, 30); + __m128i vd = _mm_or_si128(_mm_or_si128(vr, vg), _mm_or_si128(vb, va)); + vd = _mm_shuffle_epi32(vd, _MM_SHUFFLE(3, 1, 2, 0)); + _mm_storel_epi64((__m128i*)dest, vd); + dest += 2; + } + + for (; i < count; ++i) + *dest++ = qConvertRgb64ToRgb30(*buffer++); +} +#endif + static void QT_FASTCALL destStore64ARGB32(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) { uint *dest = (uint*)rasterBuffer->scanLine(y) + x; @@ -999,13 +1286,25 @@ static void QT_FASTCALL destStore64ARGB32(QRasterBuffer *rasterBuffer, int x, in } } +static void QT_FASTCALL destStore64RGBA8888(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) +{ + uint *dest = (uint*)rasterBuffer->scanLine(y) + x; + for (int i = 0; i < length; ++i) { + dest[i] = ARGB2RGBA(buffer[i].unpremultiplied().toArgb32()); + } +} + template static void QT_FASTCALL destStore64RGB30(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length) { uint *dest = (uint*)rasterBuffer->scanLine(y) + x; +#ifdef __SSE2__ + qConvertARGB64PMToA2RGB30PM_sse2(dest, buffer, length); +#else for (int i = 0; i < length; ++i) { dest[i] = qConvertRgb64ToRgb30(buffer[i]); } +#endif } static DestStoreProc destStoreProc[QImage::NImageFormats] = @@ -1056,7 +1355,7 @@ static DestStoreProc64 destStoreProc64[QImage::NImageFormats] = destStore64, // Format_RGB444 destStore64, // Format_ARGB4444_Premultiplied destStore64, // Format_RGBX8888 - destStore64, // Format_RGBA8888 + destStore64RGBA8888, // Format_RGBA8888 destStore64, // Format_RGBA8888_Premultiplied destStore64RGB30, // Format_BGR30 destStore64RGB30, // Format_A2BGR30_Premultiplied @@ -1121,6 +1420,21 @@ static const uint *QT_FASTCALL fetchUntransformedRGB16(uint *buffer, const Opera return buffer; } +static const QRgba64 *QT_FASTCALL fetchUntransformed64(QRgba64 *buffer, const Operator *, + const QSpanData *data, int y, int x, int length) +{ + const QPixelLayout *layout = &qPixelLayouts[data->texture.format]; + const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0; + if (layout->bpp != QPixelLayout::BPP32) { + uint buffer32[buffer_size]; + const uint *ptr = qFetchPixels[layout->bpp](buffer32, data->texture.scanLine(y), x, length); + return layout->convertToARGB64PM(buffer, ptr, length, layout, clut); + } else { + const uint *src = (const uint *)data->texture.scanLine(y) + x; + return layout->convertToARGB64PM(buffer, src, length, layout, clut); + } +} + // blendType is either BlendTransformed or BlendTransformedTiled template static const uint *QT_FASTCALL fetchTransformedARGB32PM(uint *buffer, const Operator *, const QSpanData *data, @@ -1188,7 +1502,91 @@ static const uint *QT_FASTCALL fetchTransformedARGB32PM(uint *buffer, const Oper px = qBound(0, px, image_width - 1); py = qBound(0, py, image_height - 1); } - *b = reinterpret_cast(data->texture.scanLine(py))[px]; + *b = reinterpret_cast(data->texture.scanLine(py))[px]; + + fx += fdx; + fy += fdy; + fw += fdw; + //force increment to avoid /0 + if (!fw) { + fw += fdw; + } + ++b; + } + } + return buffer; +} + +template /* either BlendTransformed or BlendTransformedTiled */ +static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) +{ + int image_width = data->texture.width; + int image_height = data->texture.height; + + const qreal cx = x + qreal(0.5); + const qreal cy = y + qreal(0.5); + + const QPixelLayout *layout = &qPixelLayouts[data->texture.format]; + FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + + const uint *end = buffer + length; + uint *b = buffer; + if (data->fast_matrix) { + // The increment pr x in the scanline + int fdx = (int)(data->m11 * fixed_scale); + int fdy = (int)(data->m12 * fixed_scale); + + int fx = int((data->m21 * cy + + data->m11 * cx + data->dx) * fixed_scale); + int fy = int((data->m22 * cy + + data->m12 * cx + data->dy) * fixed_scale); + + while (b < end) { + int px = fx >> 16; + int py = fy >> 16; + + if (blendType == BlendTransformedTiled) { + px %= image_width; + py %= image_height; + if (px < 0) px += image_width; + if (py < 0) py += image_height; + } else { + px = qBound(0, px, image_width - 1); + py = qBound(0, py, image_height - 1); + } + *b = fetch(data->texture.scanLine(py), px); + + fx += fdx; + fy += fdy; + ++b; + } + } else { + const qreal fdx = data->m11; + const qreal fdy = data->m12; + const qreal fdw = data->m13; + + qreal fx = data->m21 * cy + data->m11 * cx + data->dx; + qreal fy = data->m22 * cy + data->m12 * cx + data->dy; + qreal fw = data->m23 * cy + data->m13 * cx + data->m33; + + while (b < end) { + const qreal iw = fw == 0 ? 1 : 1 / fw; + const qreal tx = fx * iw; + const qreal ty = fy * iw; + int px = int(tx) - (tx < 0); + int py = int(ty) - (ty < 0); + + if (blendType == BlendTransformedTiled) { + px %= image_width; + py %= image_height; + if (px < 0) px += image_width; + if (py < 0) py += image_height; + } else { + px = qBound(0, px, image_width - 1); + py = qBound(0, py, image_height - 1); + } + *b = fetch(data->texture.scanLine(py), px); fx += fdx; fy += fdy; @@ -1200,12 +1598,13 @@ static const uint *QT_FASTCALL fetchTransformedARGB32PM(uint *buffer, const Oper ++b; } } - return buffer; + const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0; + return layout->convertToARGB32PM(buffer, buffer, length, layout, clut); } template /* either BlendTransformed or BlendTransformedTiled */ -static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data, - int y, int x, int length) +static const QRgba64 *QT_FASTCALL fetchTransformed64(QRgba64 *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) { int image_width = data->texture.width; int image_height = data->texture.height; @@ -1215,9 +1614,10 @@ static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QPixelLayout *layout = &qPixelLayouts[data->texture.format]; FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0; - const uint *end = buffer + length; - uint *b = buffer; + uint buffer32[buffer_size]; + QRgba64 *b = buffer; if (data->fast_matrix) { // The increment pr x in the scanline int fdx = (int)(data->m11 * fixed_scale); @@ -1228,7 +1628,13 @@ static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale); - while (b < end) { + int i = 0, j = 0; + while (i < length) { + if (j == buffer_size) { + layout->convertToARGB64PM(b, buffer32, buffer_size, layout, clut); + b += buffer_size; + j = 0; + } int px = fx >> 16; int py = fy >> 16; @@ -1241,11 +1647,15 @@ static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, px = qBound(0, px, image_width - 1); py = qBound(0, py, image_height - 1); } - *b = fetch(data->texture.scanLine(py), px); + buffer32[j] = fetch(data->texture.scanLine(py), px); fx += fdx; fy += fdy; - ++b; + ++i; ++j; + } + if (j > 0) { + layout->convertToARGB64PM(b, buffer32, j, layout, clut); + b += j; } } else { const qreal fdx = data->m11; @@ -1256,7 +1666,13 @@ static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, qreal fy = data->m22 * cy + data->m12 * cx + data->dy; qreal fw = data->m23 * cy + data->m13 * cx + data->m33; - while (b < end) { + int i = 0, j = 0; + while (i < length) { + if (j == buffer_size) { + layout->convertToARGB64PM(b, buffer32, buffer_size, layout, clut); + b += buffer_size; + j = 0; + } const qreal iw = fw == 0 ? 1 : 1 / fw; const qreal tx = fx * iw; const qreal ty = fy * iw; @@ -1272,7 +1688,7 @@ static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, px = qBound(0, px, image_width - 1); py = qBound(0, py, image_height - 1); } - *b = fetch(data->texture.scanLine(py), px); + buffer32[j] = fetch(data->texture.scanLine(py), px); fx += fdx; fy += fdy; @@ -1281,11 +1697,14 @@ static const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, if (!fw) { fw += fdw; } - ++b; + ++i; ++j; + } + if (j > 0) { + layout->convertToARGB64PM(b, buffer32, j, layout, clut); + b += j; } } - const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0; - return layout->convertToARGB32PM(buffer, buffer, length, layout, clut); + return buffer; } /** \internal @@ -1415,6 +1834,41 @@ static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint } #endif +#if defined(__SSE2__) +static inline QRgba64 interpolate_4_pixels_rgb64(QRgba64 t[], QRgba64 b[], uint distx, uint disty) +{ + const __m128i vdistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(distx), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vidistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(0x10000 - distx), _MM_SHUFFLE(0, 0, 0, 0)); + + __m128i vt = _mm_loadu_si128((const __m128i*)t); + if (disty) { + __m128i vb = _mm_loadu_si128((const __m128i*)b); + vt = _mm_mulhi_epu16(vt, _mm_set1_epi16(0x10000 - disty)); + vb = _mm_mulhi_epu16(vb, _mm_set1_epi16(disty)); + vt = _mm_add_epi16(vt, vb); + } + vt = _mm_mulhi_epu16(vt, _mm_unpacklo_epi64(vidistx, vdistx)); + vt = _mm_add_epi16(vt, _mm_srli_si128(vt, 8)); +#ifdef Q_PROCESSOR_X86_64 + return QRgba64::fromRgba64(_mm_cvtsi128_si64(vt)); +#else + QRgba64 out; + _mm_storel_epi64((__m128i*)&out, vt); + return out; +#endif +} +#else +static inline QRgba64 interpolate_4_pixels_rgb64(QRgba64 t[], QRgba64 b[], uint distx, uint disty) +{ + const uint dx = distx>>8; + const uint dy = disty>>8; + const uint idx = 256 - dx; + const uint idy = 256 - dy; + QRgba64 xtop = interpolate256(t[0], idx, t[1], dx); + QRgba64 xbot = interpolate256(b[0], idx, b[1], dx); + return interpolate256(xtop, idy, xbot, dy); +} +#endif template void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2); @@ -2280,6 +2734,349 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper return buffer; } +template +static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, const Operator *, + const QSpanData *data, int y, int x, int length) +{ + const QPixelLayout *layout = &qPixelLayouts[data->texture.format]; + const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0; + + int image_width = data->texture.width; + int image_height = data->texture.height; + + int image_x1 = data->texture.x1; + int image_y1 = data->texture.y1; + int image_x2 = data->texture.x2 - 1; + int image_y2 = data->texture.y2 - 1; + + const qreal cx = x + qreal(0.5); + const qreal cy = y + qreal(0.5); + + const qreal fdx = data->m11; + const qreal fdy = data->m12; + const qreal fdw = data->m13; + + if (data->fast_matrix) { + // The increment pr x in the scanline + int fdx = (int)(data->m11 * fixed_scale); + int fdy = (int)(data->m12 * fixed_scale); + + int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale); + int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale); + + fx -= half_point; + fy -= half_point; + + if (fdy == 0) { //simple scale, no rotation + int y1 = (fy >> 16); + int y2; + fetchTransformedBilinear_pixelBounds(image_height, image_y1, image_y2, y1, y2); + const uchar *s1 = data->texture.scanLine(y1); + const uchar *s2 = data->texture.scanLine(y2); + + FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + uint sbuf1[buffer_size]; + uint sbuf2[buffer_size]; + QRgba64 buf1[buffer_size]; + QRgba64 buf2[buffer_size]; + QRgba64 *b = buffer; + while (length) { + int len = qMin(length, buffer_size / 2); + int fracX = fx; + int i = 0; + int disty = (fy & 0x0000ffff); +#if defined(__SSE2__) + const __m128i vdy = _mm_set1_epi16(disty); + const __m128i vidy = _mm_set1_epi16(0x10000 - disty); + if (blendType != BlendTransformedBilinearTiled && layout->bpp == QPixelLayout::BPP32) { + for (; i < len; ++i) { + int x1 = (fx >> 16); + int x2; + fetchTransformedBilinear_pixelBounds(image_width, image_x1, image_x2, x1, x2); + if (x1 != x2) + break; + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + fx += fdx; + } + + const __m128i v_fdx = _mm_set1_epi32(fdx*4); + __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx); + for (; i < len-3; i+=4) { + int offset = _mm_extract_epi16(v_fx, 1); + sbuf1[i * 2 + 0] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[offset + 1]; + offset = _mm_extract_epi16(v_fx, 3); + sbuf1[i * 2 + 2] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 3] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 2] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 3] = ((const uint*)s2)[offset + 1]; + offset = _mm_extract_epi16(v_fx, 5); + sbuf1[i * 2 + 4] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 5] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 4] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 5] = ((const uint*)s2)[offset + 1]; + offset = _mm_extract_epi16(v_fx, 7); + sbuf1[i * 2 + 6] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 7] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 6] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 7] = ((const uint*)s2)[offset + 1]; + v_fx = _mm_add_epi32(v_fx, v_fdx); + } + fx = _mm_cvtsi128_si32(v_fx); + } +#endif + for (; i < len; ++i) { + int x1 = (fx >> 16); + int x2; + fetchTransformedBilinear_pixelBounds(image_width, image_x1, image_x2, x1, x2); + + if (layout->bpp == QPixelLayout::BPP32) { + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + + } else { + sbuf1[i * 2 + 0] = fetch(s1, x1); + sbuf1[i * 2 + 1] = fetch(s1, x2); + sbuf2[i * 2 + 0] = fetch(s2, x1); + sbuf2[i * 2 + 1] = fetch(s2, x2); + } + + fx += fdx; + } + layout->convertToARGB64PM(buf1, sbuf1, len * 2, layout, clut); + if (disty) + layout->convertToARGB64PM(buf2, sbuf2, len * 2, layout, clut); + + for (int i = 0; i < len; ++i) { + int distx = (fracX & 0x0000ffff); +#if defined(__SSE2__) + const __m128i vdistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(distx), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vidistx = _mm_shufflelo_epi16(_mm_cvtsi32_si128(0x10000 - distx), _MM_SHUFFLE(0, 0, 0, 0)); + __m128i vt = _mm_loadu_si128((const __m128i*)(buf1 + i*2)); + if (disty) { + __m128i vb = _mm_loadu_si128((const __m128i*)(buf2 + i*2)); + vt = _mm_mulhi_epu16(vt, vidy); + vb = _mm_mulhi_epu16(vb, vdy); + vt = _mm_add_epi16(vt, vb); + } + vt = _mm_mulhi_epu16(vt, _mm_unpacklo_epi64(vidistx, vdistx)); + vt = _mm_add_epi16(vt, _mm_srli_si128(vt, 8)); + _mm_storel_epi64((__m128i*)(b+i), vt); +#else + b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty); +#endif + fracX += fdx; + } + length -= len; + b += len; + } + } else { //rotation + FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + uint sbuf1[buffer_size]; + uint sbuf2[buffer_size]; + QRgba64 buf1[buffer_size]; + QRgba64 buf2[buffer_size]; + QRgba64 *end = buffer + length; + QRgba64 *b = buffer; + + while (b < end) { + int len = qMin(length, buffer_size / 2); + int fracX = fx; + int fracY = fy; + int i = 0; +#if defined(__SSE2__) + if (blendType != BlendTransformedBilinearTiled && layout->bpp == QPixelLayout::BPP32) { + for (; i < len; ++i) { + int x1 = (fx >> 16); + int x2; + int y1 = (fy >> 16); + int y2; + fetchTransformedBilinear_pixelBounds(image_width, image_x1, image_x2, x1, x2); + fetchTransformedBilinear_pixelBounds(image_height, image_y1, image_y2, y1, y2); + if (x1 != x2 && y1 != y2) + break; + const uchar *s1 = data->texture.scanLine(y1); + const uchar *s2 = data->texture.scanLine(y2); + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + fx += fdx; + fy += fdy; + } + + const __m128i v_fdx = _mm_set1_epi32(fdx*4); + const __m128i v_fdy = _mm_set1_epi32(fdy*4); + __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx); + __m128i v_fy = _mm_setr_epi32(fy, fy + fdy, fy + fdy + fdy, fy + fdy + fdy + fdy); + const int bytesPerLine = data->texture.bytesPerLine; + const uchar *s1 = data->texture.imageData; + const uchar *s2 = s1 + bytesPerLine; + const __m128i vbpl = _mm_shufflelo_epi16(_mm_cvtsi32_si128(bytesPerLine/4), _MM_SHUFFLE(0, 0, 0, 0)); + for (; i < len-3; i+=4) { + if (fdx > 0 && (short)_mm_extract_epi16(v_fx, 7) >= image_x2) + break; + if (fdx < 0 && (short)_mm_extract_epi16(v_fx, 7) < image_x1) + break; + if (fdy > 0 && (short)_mm_extract_epi16(v_fy, 7) >= image_y2) + break; + if (fdy < 0 && (short)_mm_extract_epi16(v_fy, 7) < image_y1) + break; + const __m128i vy = _mm_packs_epi32(_mm_srai_epi32(v_fy, 16), _mm_setzero_si128()); + __m128i voffset = _mm_unpacklo_epi16(_mm_mullo_epi16(vy, vbpl), _mm_mulhi_epu16(vy, vbpl)); + voffset = _mm_add_epi32(voffset, _mm_srli_epi32(v_fx, 16)); + + int offset = _mm_cvtsi128_si32(voffset); voffset = _mm_srli_si128(voffset, 4); + sbuf1[i * 2 + 0] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[offset + 1]; + offset = _mm_cvtsi128_si32(voffset); voffset = _mm_srli_si128(voffset, 4); + sbuf1[i * 2 + 2] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 3] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 2] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 3] = ((const uint*)s2)[offset + 1]; + offset = _mm_cvtsi128_si32(voffset); voffset = _mm_srli_si128(voffset, 4); + sbuf1[i * 2 + 4] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 5] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 4] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 5] = ((const uint*)s2)[offset + 1]; + offset = _mm_cvtsi128_si32(voffset); + sbuf1[i * 2 + 6] = ((const uint*)s1)[offset]; + sbuf1[i * 2 + 7] = ((const uint*)s1)[offset + 1]; + sbuf2[i * 2 + 6] = ((const uint*)s2)[offset]; + sbuf2[i * 2 + 7] = ((const uint*)s2)[offset + 1]; + + v_fx = _mm_add_epi32(v_fx, v_fdx); + v_fy = _mm_add_epi32(v_fy, v_fdy); + } + fx = _mm_cvtsi128_si32(v_fx); + fy = _mm_cvtsi128_si32(v_fy); + } +#endif + for (; i < len; ++i) { + int x1 = (fx >> 16); + int x2; + int y1 = (fy >> 16); + int y2; + fetchTransformedBilinear_pixelBounds(image_width, image_x1, image_x2, x1, x2); + fetchTransformedBilinear_pixelBounds(image_height, image_y1, image_y2, y1, y2); + + const uchar *s1 = data->texture.scanLine(y1); + const uchar *s2 = data->texture.scanLine(y2); + + if (layout->bpp == QPixelLayout::BPP32) { + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + + } else { + sbuf1[i * 2 + 0] = fetch(s1, x1); + sbuf1[i * 2 + 1] = fetch(s1, x2); + sbuf2[i * 2 + 0] = fetch(s2, x1); + sbuf2[i * 2 + 1] = fetch(s2, x2); + } + + fx += fdx; + fy += fdy; + } + layout->convertToARGB64PM(buf1, sbuf1, len * 2, layout, clut); + layout->convertToARGB64PM(buf2, sbuf2, len * 2, layout, clut); + + for (int i = 0; i < len; ++i) { + int distx = (fracX & 0x0000ffff); + int disty = (fracY & 0x0000ffff); + b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty); + fracX += fdx; + fracY += fdy; + } + + length -= len; + b += len; + } + } + } else { + qreal fx = data->m21 * cy + data->m11 * cx + data->dx; + qreal fy = data->m22 * cy + data->m12 * cx + data->dy; + qreal fw = data->m23 * cy + data->m13 * cx + data->m33; + + FetchPixelFunc fetch = qFetchPixel[layout->bpp]; + uint sbuf1[buffer_size]; + uint sbuf2[buffer_size]; + QRgba64 buf1[buffer_size]; + QRgba64 buf2[buffer_size]; + QRgba64 *b = buffer; + + int distxs[buffer_size / 2]; + int distys[buffer_size / 2]; + + while (length) { + int len = qMin(length, buffer_size / 2); + for (int i = 0; i < len; ++i) { + const qreal iw = fw == 0 ? 1 : 1 / fw; + const qreal px = fx * iw - qreal(0.5); + const qreal py = fy * iw - qreal(0.5); + + int x1 = int(px) - (px < 0); + int x2; + int y1 = int(py) - (py < 0); + int y2; + + distxs[i] = int((px - x1) * (1<<16)); + distys[i] = int((py - y1) * (1<<16)); + + fetchTransformedBilinear_pixelBounds(image_width, image_x1, image_x2, x1, x2); + fetchTransformedBilinear_pixelBounds(image_height, image_y1, image_y2, y1, y2); + + const uchar *s1 = data->texture.scanLine(y1); + const uchar *s2 = data->texture.scanLine(y2); + + if (layout->bpp == QPixelLayout::BPP32) { + sbuf1[i * 2 + 0] = ((const uint*)s1)[x1]; + sbuf1[i * 2 + 1] = ((const uint*)s1)[x2]; + sbuf2[i * 2 + 0] = ((const uint*)s2)[x1]; + sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; + + } else { + sbuf1[i * 2 + 0] = fetch(s1, x1); + sbuf1[i * 2 + 1] = fetch(s1, x2); + sbuf2[i * 2 + 0] = fetch(s2, x1); + sbuf2[i * 2 + 1] = fetch(s2, x2); + } + + fx += fdx; + fy += fdy; + fw += fdw; + //force increment to avoid /0 + if (!fw) + fw += fdw; + } + + layout->convertToARGB64PM(buf1, sbuf1, len * 2, layout, clut); + layout->convertToARGB64PM(buf2, sbuf2, len * 2, layout, clut); + + for (int i = 0; i < len; ++i) { + int distx = distxs[i]; + int disty = distys[i]; + b[i] = interpolate_4_pixels_rgb64(buf1 + i*2, buf2 + i*2, distx, disty); + } + + length -= len; + b += len; + } + } + + return buffer; +} + static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { // Untransformed { @@ -2448,6 +3245,174 @@ static SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = { }, }; +static SourceFetchProc64 sourceFetch64[NBlendTypes][QImage::NImageFormats] = { + // Untransformed + { + 0, // Invalid + fetchUntransformed64, // Mono + fetchUntransformed64, // MonoLsb + fetchUntransformed64, // Indexed8 + fetchUntransformed64, // RGB32 + fetchUntransformed64, // ARGB32 + fetchUntransformed64, // ARGB32_Premultiplied + fetchUntransformed64, // RGB16 + fetchUntransformed64, // ARGB8565_Premultiplied + fetchUntransformed64, // RGB666 + fetchUntransformed64, // ARGB6666_Premultiplied + fetchUntransformed64, // RGB555 + fetchUntransformed64, // ARGB8555_Premultiplied + fetchUntransformed64, // RGB888 + fetchUntransformed64, // RGB444 + fetchUntransformed64, // ARGB4444_Premultiplied + fetchUntransformed64, // RGBX8888 + fetchUntransformed64, // RGBA8888 + fetchUntransformed64, // RGBA8888_Premultiplied + fetchUntransformed64, // Format_BGR30 + fetchUntransformed64, // Format_A2BGR30_Premultiplied + fetchUntransformed64, // Format_RGB30 + fetchUntransformed64, // Format_A2RGB30_Premultiplied + fetchUntransformed64, // Alpha8 + fetchUntransformed64, // Grayscale8 + }, + // Tiled + { + 0, // Invalid + fetchUntransformed64, // Mono + fetchUntransformed64, // MonoLsb + fetchUntransformed64, // Indexed8 + fetchUntransformed64, // RGB32 + fetchUntransformed64, // ARGB32 + fetchUntransformed64, // ARGB32_Premultiplied + fetchUntransformed64, // RGB16 + fetchUntransformed64, // ARGB8565_Premultiplied + fetchUntransformed64, // RGB666 + fetchUntransformed64, // ARGB6666_Premultiplied + fetchUntransformed64, // RGB555 + fetchUntransformed64, // ARGB8555_Premultiplied + fetchUntransformed64, // RGB888 + fetchUntransformed64, // RGB444 + fetchUntransformed64, // ARGB4444_Premultiplied + fetchUntransformed64, // RGBX8888 + fetchUntransformed64, // RGBA8888 + fetchUntransformed64, // RGBA8888_Premultiplied + fetchUntransformed64, // BGR30 + fetchUntransformed64, // A2BGR30_Premultiplied + fetchUntransformed64, // RGB30 + fetchUntransformed64, // A2RGB30_Premultiplied + fetchUntransformed64, // Alpha8 + fetchUntransformed64, // Grayscale8 + }, + // Transformed + { + 0, // Invalid + fetchTransformed64, // Mono + fetchTransformed64, // MonoLsb + fetchTransformed64, // Indexed8 + fetchTransformed64, // RGB32 + fetchTransformed64, // ARGB32 + fetchTransformed64, // ARGB32_Premultiplied + fetchTransformed64, // RGB16 + fetchTransformed64, // ARGB8565_Premultiplied + fetchTransformed64, // RGB666 + fetchTransformed64, // ARGB6666_Premultiplied + fetchTransformed64, // RGB555 + fetchTransformed64, // ARGB8555_Premultiplied + fetchTransformed64, // RGB888 + fetchTransformed64, // RGB444 + fetchTransformed64, // ARGB4444_Premultiplied + fetchTransformed64, // RGBX8888 + fetchTransformed64, // RGBA8888 + fetchTransformed64, // RGBA8888_Premultiplied + fetchTransformed64, // BGR30 + fetchTransformed64, // A2BGR30_Premultiplied + fetchTransformed64, // RGB30 + fetchTransformed64, // A2RGB30_Premultiplied + fetchTransformed64, // Alpah8 + fetchTransformed64, // Grayscale8 + }, + { + 0, // TransformedTiled + fetchTransformed64, // Mono + fetchTransformed64, // MonoLsb + fetchTransformed64, // Indexed8 + fetchTransformed64, // RGB32 + fetchTransformed64, // ARGB32 + fetchTransformed64, // ARGB32_Premultiplied + fetchTransformed64, // RGB16 + fetchTransformed64, // ARGB8565_Premultiplied + fetchTransformed64, // RGB666 + fetchTransformed64, // ARGB6666_Premultiplied + fetchTransformed64, // RGB555 + fetchTransformed64, // ARGB8555_Premultiplied + fetchTransformed64, // RGB888 + fetchTransformed64, // RGB444 + fetchTransformed64, // ARGB4444_Premultiplied + fetchTransformed64, // RGBX8888 + fetchTransformed64, // RGBA8888 + fetchTransformed64, // RGBA8888_Premultiplied + fetchTransformed64, // BGR30 + fetchTransformed64, // A2BGR30_Premultiplied + fetchTransformed64, // RGB30 + fetchTransformed64, // A2RGB30_Premultiplied + fetchTransformed64, // Alpha8 + fetchTransformed64, // Grayscale8 + }, + { + 0, // Bilinear + fetchTransformedBilinear64, // Mono + fetchTransformedBilinear64, // MonoLsb + fetchTransformedBilinear64, // Indexed8 + fetchTransformedBilinear64, // RGB32 + fetchTransformedBilinear64, // ARGB32 + fetchTransformedBilinear64, // ARGB32_Premultiplied + fetchTransformedBilinear64, // RGB16 + fetchTransformedBilinear64, // ARGB8565_Premultiplied + fetchTransformedBilinear64, // RGB666 + fetchTransformedBilinear64, // ARGB6666_Premultiplied + fetchTransformedBilinear64, // RGB555 + fetchTransformedBilinear64, // ARGB8555_Premultiplied + fetchTransformedBilinear64, // RGB888 + fetchTransformedBilinear64, // RGB444 + fetchTransformedBilinear64, // ARGB4444_Premultiplied + fetchTransformedBilinear64, // RGBX8888 + fetchTransformedBilinear64, // RGBA8888 + fetchTransformedBilinear64, // RGBA8888_Premultiplied + fetchTransformedBilinear64, // BGR30 + fetchTransformedBilinear64, // A2BGR30_Premultiplied + fetchTransformedBilinear64, // RGB30 + fetchTransformedBilinear64, // A2RGB30_Premultiplied + fetchTransformedBilinear64, // Alpha8 + fetchTransformedBilinear64, // Grayscale8 + }, + { + 0, // BilinearTiled + fetchTransformedBilinear64, // Mono + fetchTransformedBilinear64, // MonoLsb + fetchTransformedBilinear64, // Indexed8 + fetchTransformedBilinear64, // RGB32 + fetchTransformedBilinear64, // ARGB32 + fetchTransformedBilinear64, // ARGB32_Premultiplied + fetchTransformedBilinear64, // RGB16 + fetchTransformedBilinear64, // ARGB8565_Premultiplied + fetchTransformedBilinear64, // RGB666 + fetchTransformedBilinear64, // ARGB6666_Premultiplied + fetchTransformedBilinear64, // RGB555 + fetchTransformedBilinear64, // ARGB8555_Premultiplied + fetchTransformedBilinear64, // RGB888 + fetchTransformedBilinear64, // RGB444 + fetchTransformedBilinear64, // ARGB4444_Premultiplied + fetchTransformedBilinear64, // RGBX8888 + fetchTransformedBilinear64, // RGBA8888 + fetchTransformedBilinear64, // RGBA8888_Premultiplied + fetchTransformedBilinear64, // BGR30 + fetchTransformedBilinear64, // A2BGR30_Premultiplied + fetchTransformedBilinear64, // RGB30 + fetchTransformedBilinear64, // A2RGB30_Premultiplied + fetchTransformedBilinear64, // Alpha8 + fetchTransformedBilinear64, // Grayscale8 + }, +}; + #define FIXPT_BITS 8 #define FIXPT_SIZE (1<texture.format]; - op.srcFetch64 = 0; // sourceFetch64[getBlendType(data)][data->texture.format]; + op.srcFetch64 = sourceFetch64[getBlendType(data)][data->texture.format]; solidSource = !data->texture.hasAlpha; default: break; @@ -6826,6 +7791,16 @@ inline static void qt_bitmapblit_rgba8888(QRasterBuffer *rasterBuffer, map, mapWidth, mapHeight, mapStride); } +template +inline static void qt_bitmapblit_rgb30(QRasterBuffer *rasterBuffer, + int x, int y, const QRgba64 &color, + const uchar *map, + int mapWidth, int mapHeight, int mapStride) +{ + qt_bitmapblit_template(rasterBuffer, x, y, qConvertRgb64ToRgb30(color), + map, mapWidth, mapHeight, mapStride); +} + inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 &color, const uchar *map, @@ -7348,7 +8323,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = { blend_color_generic_rgb64, blend_src_generic_rgb64, - 0, + qt_bitmapblit_rgb30, 0, 0, qt_rectfill_rgb30 @@ -7357,7 +8332,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = { blend_color_generic_rgb64, blend_src_generic_rgb64, - 0, + qt_bitmapblit_rgb30, 0, 0, qt_rectfill_rgb30 @@ -7366,7 +8341,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = { blend_color_generic_rgb64, blend_src_generic_rgb64, - 0, + qt_bitmapblit_rgb30, 0, 0, qt_rectfill_rgb30 @@ -7375,7 +8350,7 @@ DrawHelper qDrawHelper[QImage::NImageFormats] = { blend_color_generic_rgb64, blend_src_generic_rgb64, - 0, + qt_bitmapblit_rgb30, 0, 0, qt_rectfill_rgb30 diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 501f1ce033..53f4db6fce 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -1139,6 +1139,8 @@ void QT_FASTCALL rasterop_solid_NotDestination(uint *dest, int length, uint colo struct QPixelLayout; typedef const uint *(QT_FASTCALL *ConvertFunc)(uint *buffer, const uint *src, int count, const QPixelLayout *layout, const QRgb *clut); +typedef const QRgba64 *(QT_FASTCALL *ConvertFunc64)(QRgba64 *buffer, const uint *src, int count, + const QPixelLayout *layout, const QRgb *clut); struct QPixelLayout { @@ -1168,6 +1170,7 @@ struct QPixelLayout ConvertFunc convertToARGB32PM; ConvertFunc convertFromARGB32PM; ConvertFunc convertFromRGB32; + ConvertFunc64 convertToARGB64PM; }; typedef const uint *(QT_FASTCALL *FetchPixelsFunc)(uint *buffer, const uchar *src, int index, int count); diff --git a/src/gui/painting/qrgba64_p.h b/src/gui/painting/qrgba64_p.h index 0301c2a7de..c6cbe666ac 100644 --- a/src/gui/painting/qrgba64_p.h +++ b/src/gui/painting/qrgba64_p.h @@ -36,6 +36,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -52,20 +53,36 @@ inline QRgba64 multiplyAlpha256(QRgba64 rgba64, uint alpha256) (rgba64.alpha() * alpha256) >> 8); } -inline QRgba64 multiplyAlpha255(QRgba64 rgba64, uint alpha255) -{ - return QRgba64::fromRgba64(qt_div_255(rgba64.red() * alpha255), - qt_div_255(rgba64.green() * alpha255), - qt_div_255(rgba64.blue() * alpha255), - qt_div_255(rgba64.alpha() * alpha255)); -} - inline QRgba64 multiplyAlpha65535(QRgba64 rgba64, uint alpha65535) { +#ifdef __SSE2__ + const __m128i va = _mm_shufflelo_epi16(_mm_cvtsi32_si128(alpha65535), _MM_SHUFFLE(0, 0, 0, 0)); + __m128i vs = _mm_loadl_epi64((__m128i*)&rgba64); + vs = _mm_unpacklo_epi16(_mm_mullo_epi16(vs, va), _mm_mulhi_epu16(vs, va)); + vs = _mm_add_epi32(vs, _mm_srli_epi32(vs, 16)); + vs = _mm_add_epi32(vs, _mm_set1_epi32(0x8000)); + vs = _mm_srai_epi32(vs, 16); + vs = _mm_packs_epi32(vs, _mm_setzero_si128()); + _mm_storel_epi64((__m128i*)&rgba64, vs); + return rgba64; +#else return QRgba64::fromRgba64(qt_div_65535(rgba64.red() * alpha65535), qt_div_65535(rgba64.green() * alpha65535), qt_div_65535(rgba64.blue() * alpha65535), qt_div_65535(rgba64.alpha() * alpha65535)); +#endif +} + +inline QRgba64 multiplyAlpha255(QRgba64 rgba64, uint alpha255) +{ +#ifdef __SSE2__ + return multiplyAlpha65535(rgba64, alpha255 * 257); +#else + return QRgba64::fromRgba64(qt_div_255(rgba64.red() * alpha255), + qt_div_255(rgba64.green() * alpha255), + qt_div_255(rgba64.blue() * alpha255), + qt_div_255(rgba64.alpha() * alpha255)); +#endif } inline QRgba64 interpolate256(QRgba64 x, uint alpha1, QRgba64 y, uint alpha2) -- cgit v1.2.3 From 7432c7c08a6709a12a143d48fbaa9927962edae8 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 7 Apr 2015 11:20:08 +0200 Subject: Cleanup and optimization of qimage smoothscale Cleaning up smoothscale code. Upscaling is improved using existing optimized interpolation methods, and downscale is given SSE4.1 optimized versions. Change-Id: I7cdc256c26850948aef7dae26fda1622be6b8179 Reviewed-by: Gunnar Sletta --- src/gui/painting/painting.pri | 3 +- src/gui/painting/qdrawhelper.cpp | 38 -- src/gui/painting/qdrawhelper_p.h | 36 + src/gui/painting/qimagescale.cpp | 1155 +++++++++++++-------------------- src/gui/painting/qimagescale_p.h | 9 + src/gui/painting/qimagescale_sse4.cpp | 247 +++++++ 6 files changed, 762 insertions(+), 726 deletions(-) create mode 100644 src/gui/painting/qimagescale_sse4.cpp (limited to 'src/gui/painting') diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 2f2d3daaf8..a861516821 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -93,7 +93,8 @@ SOURCES += \ SSE2_SOURCES += painting/qdrawhelper_sse2.cpp SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp -SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp +SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \ + painting/qimagescale_sse4.cpp AVX2_SOURCES += painting/qdrawhelper_avx2.cpp !ios { diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 57bb111538..b75018452a 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -1245,44 +1245,6 @@ static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, i } #endif -#if defined(__SSE2__) -static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) -{ - // First interpolate right and left pixels in parallel. - __m128i vl = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tl), _mm_cvtsi32_si128(bl)); - __m128i vr = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tr), _mm_cvtsi32_si128(br)); - vl = _mm_unpacklo_epi8(vl, _mm_setzero_si128()); - vr = _mm_unpacklo_epi8(vr, _mm_setzero_si128()); - vl = _mm_mullo_epi16(vl, _mm_set1_epi16(256 - distx)); - vr = _mm_mullo_epi16(vr, _mm_set1_epi16(distx)); - __m128i vtb = _mm_add_epi16(vl, vr); - vtb = _mm_srli_epi16(vtb, 8); - // vtb now contains the result of the first two interpolate calls vtb = unpacked((xbot << 64) | xtop) - - // Now the last interpolate between top and bottom interpolations. - const __m128i vidisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(256 - disty), _MM_SHUFFLE(0, 0, 0, 0)); - const __m128i vdisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(disty), _MM_SHUFFLE(0, 0, 0, 0)); - const __m128i vmuly = _mm_unpacklo_epi16(vidisty, vdisty); - vtb = _mm_unpacklo_epi16(vtb, _mm_srli_si128(vtb, 8)); - // vtb now contains the colors of top and bottom interleaved { ta, ba, tr, br, tg, bg, tb, bb } - vtb = _mm_madd_epi16(vtb, vmuly); // Multiply and horizontal add. - vtb = _mm_srli_epi32(vtb, 8); - vtb = _mm_packs_epi32(vtb, _mm_setzero_si128()); - vtb = _mm_packus_epi16(vtb, _mm_setzero_si128()); - return _mm_cvtsi128_si32(vtb); -} -#else -static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) -{ - uint idistx = 256 - distx; - uint idisty = 256 - disty; - uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); - uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); - return INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); -} -#endif - - template void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2); diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 480ba4c97b..0d391b2cec 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -605,6 +605,42 @@ static Q_ALWAYS_INLINE uint BYTE_MUL(uint x, uint a) { } #endif +#ifdef __SSE2__ +static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) +{ + // First interpolate right and left pixels in parallel. + __m128i vl = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tl), _mm_cvtsi32_si128(bl)); + __m128i vr = _mm_unpacklo_epi32(_mm_cvtsi32_si128(tr), _mm_cvtsi32_si128(br)); + vl = _mm_unpacklo_epi8(vl, _mm_setzero_si128()); + vr = _mm_unpacklo_epi8(vr, _mm_setzero_si128()); + vl = _mm_mullo_epi16(vl, _mm_set1_epi16(256 - distx)); + vr = _mm_mullo_epi16(vr, _mm_set1_epi16(distx)); + __m128i vtb = _mm_add_epi16(vl, vr); + vtb = _mm_srli_epi16(vtb, 8); + // vtb now contains the result of the first two interpolate calls vtb = unpacked((xbot << 64) | xtop) + + // Now the last interpolate between top and bottom interpolations. + const __m128i vidisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(256 - disty), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vdisty = _mm_shufflelo_epi16(_mm_cvtsi32_si128(disty), _MM_SHUFFLE(0, 0, 0, 0)); + const __m128i vmuly = _mm_unpacklo_epi16(vidisty, vdisty); + vtb = _mm_unpacklo_epi16(vtb, _mm_srli_si128(vtb, 8)); + // vtb now contains the colors of top and bottom interleaved { ta, ba, tr, br, tg, bg, tb, bb } + vtb = _mm_madd_epi16(vtb, vmuly); // Multiply and horizontal add. + vtb = _mm_srli_epi32(vtb, 8); + vtb = _mm_packs_epi32(vtb, _mm_setzero_si128()); + vtb = _mm_packus_epi16(vtb, _mm_setzero_si128()); + return _mm_cvtsi128_si32(vtb); +} +#else +static inline uint interpolate_4_pixels(uint tl, uint tr, uint bl, uint br, uint distx, uint disty) +{ + uint idistx = 256 - distx; + uint idisty = 256 - disty; + uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx); + uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx); + return INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty); +} +#endif #if Q_BYTE_ORDER == Q_BIG_ENDIAN static Q_ALWAYS_INLINE quint32 RGBA2ARGB(quint32 x) { diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp index 58e9112dd6..5f1b25e189 100644 --- a/src/gui/painting/qimagescale.cpp +++ b/src/gui/painting/qimagescale.cpp @@ -38,10 +38,6 @@ QT_BEGIN_NAMESPACE -namespace QImageScale { - struct QImageScaleInfo; -} - typedef void (*qt_qimageScaleFunc)(QImageScale::QImageScaleInfo *isi, unsigned int *dest, int dxx, int dyy, int dx, int dy, int dw, int dh, int dow, int sow); @@ -105,15 +101,7 @@ qt_qimageScaleFunc qt_qimageScaleRgb = qt_qimageScaleAARGB; namespace QImageScale { - struct QImageScaleInfo { - int *xpoints; - const unsigned int **ypoints; - int *xapoints, *yapoints; - int xup_yup; - }; - - const unsigned int** qimageCalcYPoints(const unsigned int *src, int sw, int sh, - int dh); + const unsigned int** qimageCalcYPoints(const unsigned int *src, int sw, int sh, int dh); int* qimageCalcXPoints(int sw, int dw); int* qimageCalcApoints(int s, int d, int up); QImageScaleInfo* qimageFreeScaleInfo(QImageScaleInfo *isi); @@ -134,16 +122,11 @@ using namespace QImageScale; #define G_VAL(p) (qGreen(*p)) #define B_VAL(p) (qBlue(*p)) -#define INV_XAP (256 - xapoints[x]) -#define XAP (xapoints[x]) -#define INV_YAP (256 - yapoints[dyy + y]) -#define YAP (yapoints[dyy + y]) - const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, int sw, int sh, int dh) { const unsigned int **p; - int i, j = 0, rv = 0; + int j = 0, rv = 0; qint64 val, inc; if(dh < 0){ @@ -155,12 +138,12 @@ const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, int up = qAbs(dh) >= sh; val = up ? 0x8000 * sh / dh - 0x8000 : 0; inc = (((qint64)sh) << 16) / dh; - for(i = 0; i < dh; i++){ + for (int i = 0; i < dh; i++) { p[j++] = src + qMax(0LL, val >> 16) * sw; val += inc; } - if(rv){ - for(i = dh / 2; --i >= 0; ){ + if (rv) { + for (int i = dh / 2; --i >= 0; ) { const unsigned int *tmp = p[i]; p[i] = p[dh - i - 1]; p[dh - i - 1] = tmp; @@ -171,7 +154,7 @@ const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src, int* QImageScale::qimageCalcXPoints(int sw, int dw) { - int *p, i, j = 0, rv = 0; + int *p, j = 0, rv = 0; qint64 val, inc; if(dw < 0){ @@ -183,13 +166,13 @@ int* QImageScale::qimageCalcXPoints(int sw, int dw) int up = qAbs(dw) >= sw; val = up ? 0x8000 * sw / dw - 0x8000 : 0; inc = (((qint64)sw) << 16) / dw; - for(i = 0; i < dw; i++){ + for (int i = 0; i < dw; i++) { p[j++] = qMax(0LL, val >> 16); val += inc; } - if(rv){ - for(i = dw / 2; --i >= 0; ){ + if (rv) { + for (int i = dw / 2; --i >= 0; ) { int tmp = p[i]; p[i] = p[dw - i - 1]; p[dw - i - 1] = tmp; @@ -200,7 +183,7 @@ int* QImageScale::qimageCalcXPoints(int sw, int dw) int* QImageScale::qimageCalcApoints(int s, int d, int up) { - int *p, i, j = 0, rv = 0; + int *p, j = 0, rv = 0; if(d < 0){ rv = 1; @@ -214,7 +197,7 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) val = 0x8000 * s / d - 0x8000; inc = (((qint64)s) << 16) / d; - for(i = 0; i < d; i++){ + for (int i = 0; i < d; i++) { int pos = val >> 16; if (pos < 0) p[j++] = 0; @@ -226,14 +209,12 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) } } /* scaling down */ - else{ - qint64 val, inc; - int ap, Cp; - val = 0; - inc = (((qint64)s) << 16) / d; - Cp = ((d << 14) / s) + 1; - for(i = 0; i < d; i++){ - ap = ((0x100 - ((val >> 8) & 0xff)) * Cp) >> 8; + else { + qint64 val = 0; + qint64 inc = (((qint64)s) << 16) / d; + int Cp = (((d << 14) + s - 1) / s); + for (int i = 0; i < d; i++) { + int ap = ((0x10000 - (val & 0xffff)) * Cp) >> 16; p[j] = ap | (Cp << 16); j++; val += inc; @@ -241,13 +222,13 @@ int* QImageScale::qimageCalcApoints(int s, int d, int up) } if(rv){ int tmp; - for(i = d / 2; --i >= 0; ){ + for (int i = d / 2; --i >= 0; ) { tmp = p[i]; p[i] = p[d - i - 1]; p[d - i - 1] = tmp; } } - return(p); + return p; } QImageScaleInfo* QImageScale::qimageFreeScaleInfo(QImageScaleInfo *isi) @@ -297,700 +278,500 @@ QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img, return(isi); } -/* FIXME: NEED to optimize ScaleAARGBA - currently its "ok" but needs work*/ -/* scale by area sampling */ -static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow) +static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow); + +#if defined(QT_COMPILER_SUPPORTS_SSE4_1) +template +void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); +template +void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); +template +void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); +#endif + +static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) { - const unsigned int *sptr; - unsigned int *dptr; - int x, y, end; const unsigned int **ypoints = isi->ypoints; int *xpoints = isi->xpoints; int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - end = dxx + dw; - /* scaling up both ways */ - if(isi->xup_yup == 3){ - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - /* calculate the source line we'll scan from */ - dptr = dest + dx + ((y + dy) * dow); - sptr = ypoints[dyy + y]; - if(YAP > 0){ - for(x = dxx; x < end; x++){ - int r, g, b, a; - int rr, gg, bb, aa; - const unsigned int *pix; - - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_XAP; - g = G_VAL(pix) * INV_XAP; - b = B_VAL(pix) * INV_XAP; - a = A_VAL(pix) * INV_XAP; - pix++; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; - a += A_VAL(pix) * XAP; - pix += sow; - rr = R_VAL(pix) * XAP; - gg = G_VAL(pix) * XAP; - bb = B_VAL(pix) * XAP; - aa = A_VAL(pix) * XAP; - pix--; - rr += R_VAL(pix) * INV_XAP; - gg += G_VAL(pix) * INV_XAP; - bb += B_VAL(pix) * INV_XAP; - aa += A_VAL(pix) * INV_XAP; - r = ((rr * YAP) + (r * INV_YAP)) >> 16; - g = ((gg * YAP) + (g * INV_YAP)) >> 16; - b = ((bb * YAP) + (b * INV_YAP)) >> 16; - a = ((aa * YAP) + (a * INV_YAP)) >> 16; - *dptr++ = qRgba(r, g, b, a); - } - else{ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_YAP; - g = G_VAL(pix) * INV_YAP; - b = B_VAL(pix) * INV_YAP; - a = A_VAL(pix) * INV_YAP; - pix += sow; - r += R_VAL(pix) * YAP; - g += G_VAL(pix) * YAP; - b += B_VAL(pix) * YAP; - a += A_VAL(pix) * YAP; - r >>= 8; - g >>= 8; - b >>= 8; - a >>= 8; - *dptr++ = qRgba(r, g, b, a); - } - } + int end = dxx + dw; + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + /* calculate the source line we'll scan from */ + const unsigned int *sptr = ypoints[dyy + y]; + unsigned int *dptr = dest + dx + ((y + dy) * dow); + const int yap = yapoints[dyy + y]; + if (yap > 0) { + for (int x = dxx; x < end; x++) { + const unsigned int *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + if (xap > 0) + *dptr = interpolate_4_pixels(pix[0], pix[1], pix[sow], pix[sow + 1], xap, yap); + else + *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - yap, pix[sow], yap); + dptr++; } - else{ - for(x = dxx; x < end; x++){ - int r, g, b, a; - const unsigned int *pix; - - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_XAP; - g = G_VAL(pix) * INV_XAP; - b = B_VAL(pix) * INV_XAP; - a = A_VAL(pix) * INV_XAP; - pix++; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; - a += A_VAL(pix) * XAP; - r >>= 8; - g >>= 8; - b >>= 8; - a >>= 8; - *dptr++ = qRgba(r, g, b, a); - } - else - *dptr++ = sptr[xpoints[x] ]; - } + } else { + for (int x = dxx; x < end; x++) { + const unsigned int *pix = sptr + xpoints[x]; + const int xap = xapoints[x]; + *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap); + dptr++; } } } +} + +/* scale by area sampling */ +static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + /* scaling up both ways */ + if (isi->xup_yup == 3){ + qt_qimageScaleAARGBA_up_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } /* if we're scaling down vertically */ - else if(isi->xup_yup == 1){ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cy, j; - const unsigned int *pix; - int r, g, b, a, rr, gg, bb, aa; - int yap; - - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - Cy = YAP >> 16; - yap = YAP & 0xffff; - - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * yap; - g = G_VAL(pix) * yap; - b = B_VAL(pix) * yap; - a = A_VAL(pix) * yap; - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - pix += sow; - r += R_VAL(pix) * Cy; - g += G_VAL(pix) * Cy; - b += B_VAL(pix) * Cy; - a += A_VAL(pix) * Cy; - } - if(j > 0){ - pix += sow; - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - a += A_VAL(pix) * j; - } - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x] + 1; - rr = R_VAL(pix) * yap; - gg = G_VAL(pix) * yap; - bb = B_VAL(pix) * yap; - aa = A_VAL(pix) * yap; - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - pix += sow; - rr += R_VAL(pix) * Cy; - gg += G_VAL(pix) * Cy; - bb += B_VAL(pix) * Cy; - aa += A_VAL(pix) * Cy; - } - if(j > 0){ - pix += sow; - rr += R_VAL(pix) * j; - gg += G_VAL(pix) * j; - bb += B_VAL(pix) * j; - aa += A_VAL(pix) * j; - } - r = r * INV_XAP; - g = g * INV_XAP; - b = b * INV_XAP; - a = a * INV_XAP; - r = (r + ((rr * XAP))) >> 12; - g = (g + ((gg * XAP))) >> 12; - b = (b + ((bb * XAP))) >> 12; - a = (a + ((aa * XAP))) >> 12; - } - else{ - r >>= 4; - g >>= 4; - b >>= 4; - a >>= 4; - } - *dptr = qRgba(r >> 10, g >> 10, b >> 10, a >> 10); - dptr++; - } - } + else if (isi->xup_yup == 1) { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_up_x_down_y_sse4(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGBA_up_x_down_y(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); } /* if we're scaling down horizontally */ - else if(isi->xup_yup == 2){ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cx, j; - const unsigned int *pix; - int r, g, b, a, rr, gg, bb, aa; - int xap; - - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - Cx = XAP >> 16; - xap = XAP & 0xffff; - - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * xap; - g = G_VAL(pix) * xap; - b = B_VAL(pix) * xap; - a = A_VAL(pix) * xap; - for(j = (1 << 14) - xap; j > Cx; j -= Cx){ - pix++; - r += R_VAL(pix) * Cx; - g += G_VAL(pix) * Cx; - b += B_VAL(pix) * Cx; - a += A_VAL(pix) * Cx; - } - if(j > 0){ - pix++; - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - a += A_VAL(pix) * j; - } - if(YAP > 0){ - pix = ypoints[dyy + y] + xpoints[x] + sow; - rr = R_VAL(pix) * xap; - gg = G_VAL(pix) * xap; - bb = B_VAL(pix) * xap; - aa = A_VAL(pix) * xap; - for(j = (1 << 14) - xap; j > Cx; j -= Cx){ - pix++; - rr += R_VAL(pix) * Cx; - gg += G_VAL(pix) * Cx; - bb += B_VAL(pix) * Cx; - aa += A_VAL(pix) * Cx; - } - if(j > 0){ - pix++; - rr += R_VAL(pix) * j; - gg += G_VAL(pix) * j; - bb += B_VAL(pix) * j; - aa += A_VAL(pix) * j; - } - r = r * INV_YAP; - g = g * INV_YAP; - b = b * INV_YAP; - a = a * INV_YAP; - r = (r + ((rr * YAP))) >> 12; - g = (g + ((gg * YAP))) >> 12; - b = (b + ((bb * YAP))) >> 12; - a = (a + ((aa * YAP))) >> 12; - } - else{ - r >>= 4; - g >>= 4; - b >>= 4; - a >>= 4; - } - *dptr = qRgba(r >> 10, g >> 10, b >> 10, a >> 10); - dptr++; - } - } + else if (isi->xup_yup == 2) { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_down_x_up_y_sse4(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGBA_down_x_up_y(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); } /* if we're scaling down horizontally & vertically */ - else{ - /*\ 'Correct' version, with math units prepared for MMXification: - |*| The operation 'b = (b * c) >> 16' translates to pmulhw, - |*| so the operation 'b = (b * c) >> d' would translate to - |*| psllw (16 - d), %mmb; pmulh %mmc, %mmb - \*/ - int Cx, Cy, i, j; - const unsigned int *pix; - int a, r, g, b, ax, rx, gx, bx; - int xap, yap; - - for(y = 0; y < dh; y++){ - Cy = YAP >> 16; - yap = YAP & 0xffff; - - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - Cx = XAP >> 16; - xap = XAP & 0xffff; - - sptr = ypoints[dyy + y] + xpoints[x]; - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - ax = A_VAL(pix) * xap; - - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - ax += A_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - ax += A_VAL(pix) * i; - } - - r = (rx >> 5) * yap; - g = (gx >> 5) * yap; - b = (bx >> 5) * yap; - a = (ax >> 5) * yap; - - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - ax = A_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - ax += A_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - ax += A_VAL(pix) * i; - } - - r += (rx >> 5) * Cy; - g += (gx >> 5) * Cy; - b += (bx >> 5) * Cy; - a += (ax >> 5) * Cy; - } - if(j > 0){ - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - ax = A_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - ax += A_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - ax += A_VAL(pix) * i; - } - - r += (rx >> 5) * j; - g += (gx >> 5) * j; - b += (bx >> 5) * j; - a += (ax >> 5) * j; - } - - *dptr = qRgba(r >> 23, g >> 23, b >> 23, a >> 23); - dptr++; + else { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_down_xy_sse4(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGBA_down_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } +} + +inline static void qt_qimageScaleAARGBA_helper_x(const unsigned int *pix, int xap, int Cx, int &r, int &g, int &b, int &a) +{ + r = R_VAL(pix) * xap; + g = G_VAL(pix) * xap; + b = B_VAL(pix) * xap; + a = A_VAL(pix) * xap; + int j; + for (j = (1 << 14) - xap; j > Cx; j -= Cx ){ + pix++; + r += R_VAL(pix) * Cx; + g += G_VAL(pix) * Cx; + b += B_VAL(pix) * Cx; + a += A_VAL(pix) * Cx; + } + pix++; + r += R_VAL(pix) * j; + g += G_VAL(pix) * j; + b += B_VAL(pix) * j; + a += A_VAL(pix) * j; +} + +inline static void qt_qimageScaleAARGBA_helper_y(const unsigned int *pix, int yap, int Cy, int sow, int &r, int &g, int &b, int &a) +{ + r = R_VAL(pix) * yap; + g = G_VAL(pix) * yap; + b = B_VAL(pix) * yap; + a = A_VAL(pix) * yap; + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy ){ + pix += sow; + r += R_VAL(pix) * Cy; + g += G_VAL(pix) * Cy; + b += B_VAL(pix) * Cy; + a += A_VAL(pix) * Cy; + } + pix += sow; + r += R_VAL(pix) * j; + g += G_VAL(pix) * j; + b += B_VAL(pix) * j; + a += A_VAL(pix) * j; +} + +static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int r, g, b, a; + qt_qimageScaleAARGBA_helper_y(sptr, yap, Cy, sow, r, g, b, a); + + int xap = xapoints[x]; + if (xap > 0) { + int rr, gg, bb, aa; + qt_qimageScaleAARGBA_helper_y(sptr + 1, yap, Cy, sow, rr, gg, bb, aa); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + a = a * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; + a = (a + (aa * xap)) >> 8; } + *dptr++ = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); } } } -/* scale by area sampling - IGNORE the ALPHA byte*/ -static void qt_qimageScaleAARGB(QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow) +static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) { - const unsigned int *sptr; - unsigned int *dptr; - int x, y, end; const unsigned int **ypoints = isi->ypoints; int *xpoints = isi->xpoints; int *xapoints = isi->xapoints; int *yapoints = isi->yapoints; - end = dxx + dw; - /* scaling up both ways */ - if(isi->xup_yup == 3){ - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - /* calculate the source line we'll scan from */ - dptr = dest + dx + ((y + dy) * dow); - sptr = ypoints[dyy + y]; - if(YAP > 0){ - for(x = dxx; x < end; x++){ - int r = 0, g = 0, b = 0; - int rr = 0, gg = 0, bb = 0; - const unsigned int *pix; - - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_XAP; - g = G_VAL(pix) * INV_XAP; - b = B_VAL(pix) * INV_XAP; - pix++; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; - pix += sow; - rr = R_VAL(pix) * XAP; - gg = G_VAL(pix) * XAP; - bb = B_VAL(pix) * XAP; - pix --; - rr += R_VAL(pix) * INV_XAP; - gg += G_VAL(pix) * INV_XAP; - bb += B_VAL(pix) * INV_XAP; - r = ((rr * YAP) + (r * INV_YAP)) >> 16; - g = ((gg * YAP) + (g * INV_YAP)) >> 16; - b = ((bb * YAP) + (b * INV_YAP)) >> 16; - *dptr++ = qRgba(r, g, b, 0xff); - } - else{ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_YAP; - g = G_VAL(pix) * INV_YAP; - b = B_VAL(pix) * INV_YAP; - pix += sow; - r += R_VAL(pix) * YAP; - g += G_VAL(pix) * YAP; - b += B_VAL(pix) * YAP; - r >>= 8; - g >>= 8; - b >>= 8; - *dptr++ = qRgba(r, g, b, 0xff); - } - } - } - else{ - for(x = dxx; x < end; x++){ - int r = 0, g = 0, b = 0; - const unsigned int *pix; - - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * INV_XAP; - g = G_VAL(pix) * INV_XAP; - b = B_VAL(pix) * INV_XAP; - pix++; - r += R_VAL(pix) * XAP; - g += G_VAL(pix) * XAP; - b += B_VAL(pix) * XAP; - r >>= 8; - g >>= 8; - b >>= 8; - *dptr++ = qRgba(r, g, b, 0xff); - } - else - *dptr++ = sptr[xpoints[x] ]; - } + int end = dxx + dw; + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int r, g, b, a; + qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, r, g, b, a); + + int yap = yapoints[dyy + y]; + if (yap > 0) { + int rr, gg, bb, aa; + qt_qimageScaleAARGBA_helper_x(sptr + sow, xap, Cx, rr, gg, bb, aa); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + a = a * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + a = (a + (aa * yap)) >> 8; } + *dptr = qRgba(r >> 14, g >> 14, b >> 14, a >> 14); + dptr++; } } - /* if we're scaling down vertically */ - else if(isi->xup_yup == 1){ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cy, j; - const unsigned int *pix; - int r, g, b, rr, gg, bb; - int yap; - - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - Cy = YAP >> 16; - yap = YAP & 0xffff; - - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * yap; - g = G_VAL(pix) * yap; - b = B_VAL(pix) * yap; - pix += sow; - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - r += R_VAL(pix) * Cy; - g += G_VAL(pix) * Cy; - b += B_VAL(pix) * Cy; - pix += sow; - } - if(j > 0){ - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - } - if(XAP > 0){ - pix = ypoints[dyy + y] + xpoints[x] + 1; - rr = R_VAL(pix) * yap; - gg = G_VAL(pix) * yap; - bb = B_VAL(pix) * yap; - pix += sow; - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - rr += R_VAL(pix) * Cy; - gg += G_VAL(pix) * Cy; - bb += B_VAL(pix) * Cy; - pix += sow; - } - if(j > 0){ - rr += R_VAL(pix) * j; - gg += G_VAL(pix) * j; - bb += B_VAL(pix) * j; - } - r = r * INV_XAP; - g = g * INV_XAP; - b = b * INV_XAP; - r = (r + ((rr * XAP))) >> 12; - g = (g + ((gg * XAP))) >> 12; - b = (b + ((bb * XAP))) >> 12; - } - else{ - r >>= 4; - g >>= 4; - b >>= 4; - } - *dptr = qRgba(r >> 10, g >> 10, b >> 10, 0xff); - dptr++; +} + +static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int rx, gx, bx, ax; + qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, rx, gx, bx, ax); + + int r = ((rx>>4) * yap); + int g = ((gx>>4) * yap); + int b = ((bx>>4) * yap); + int a = ((ax>>4) * yap); + + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, rx, gx, bx, ax); + r += ((rx>>4) * Cy); + g += ((gx>>4) * Cy); + b += ((bx>>4) * Cy); + a += ((ax>>4) * Cy); } + sptr += sow; + qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, rx, gx, bx, ax); + + r += ((rx>>4) * j); + g += ((gx>>4) * j); + b += ((bx>>4) * j); + a += ((ax>>4) * j); + + *dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24); + dptr++; } } +} + +static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow); + +static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow); + +static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow); + +/* scale by area sampling - IGNORE the ALPHA byte*/ +static void qt_qimageScaleAARGB(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + /* scaling up both ways */ + if (isi->xup_yup == 3) { + qt_qimageScaleAARGBA_up_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } + /* if we're scaling down vertically */ + else if (isi->xup_yup == 1) { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_up_x_down_y_sse4(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGB_up_x_down_y(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } /* if we're scaling down horizontally */ - else if(isi->xup_yup == 2){ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cx, j; - const unsigned int *pix; - int r, g, b, rr, gg, bb; - int xap; - - /* go through every scanline in the output buffer */ - for(y = 0; y < dh; y++){ - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - Cx = XAP >> 16; - xap = XAP & 0xffff; - - pix = ypoints[dyy + y] + xpoints[x]; - r = R_VAL(pix) * xap; - g = G_VAL(pix) * xap; - b = B_VAL(pix) * xap; - pix++; - for(j = (1 << 14) - xap; j > Cx; j -= Cx){ - r += R_VAL(pix) * Cx; - g += G_VAL(pix) * Cx; - b += B_VAL(pix) * Cx; - pix++; - } - if(j > 0){ - r += R_VAL(pix) * j; - g += G_VAL(pix) * j; - b += B_VAL(pix) * j; - } - if(YAP > 0){ - pix = ypoints[dyy + y] + xpoints[x] + sow; - rr = R_VAL(pix) * xap; - gg = G_VAL(pix) * xap; - bb = B_VAL(pix) * xap; - pix++; - for(j = (1 << 14) - xap; j > Cx; j -= Cx){ - rr += R_VAL(pix) * Cx; - gg += G_VAL(pix) * Cx; - bb += B_VAL(pix) * Cx; - pix++; - } - if(j > 0){ - rr += R_VAL(pix) * j; - gg += G_VAL(pix) * j; - bb += B_VAL(pix) * j; - } - r = r * INV_YAP; - g = g * INV_YAP; - b = b * INV_YAP; - r = (r + ((rr * YAP))) >> 12; - g = (g + ((gg * YAP))) >> 12; - b = (b + ((bb * YAP))) >> 12; - } - else{ - r >>= 4; - g >>= 4; - b >>= 4; - } - *dptr = qRgba(r >> 10, g >> 10, b >> 10, 0xff); - dptr++; - } - } + else if (isi->xup_yup == 2) { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_down_x_up_y_sse4(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGB_down_x_up_y(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); } - /* fully optimized (i think) - onyl change of algorithm can help */ /* if we're scaling down horizontally & vertically */ - else{ - /*\ 'Correct' version, with math units prepared for MMXification \*/ - int Cx, Cy, i, j; - const unsigned int *pix; - int r, g, b, rx, gx, bx; - int xap, yap; - - for(y = 0; y < dh; y++){ - Cy = YAP >> 16; - yap = YAP & 0xffff; - - dptr = dest + dx + ((y + dy) * dow); - for(x = dxx; x < end; x++){ - Cx = XAP >> 16; - xap = XAP & 0xffff; - - sptr = ypoints[dyy + y] + xpoints[x]; - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - } - - r = (rx >> 5) * yap; - g = (gx >> 5) * yap; - b = (bx >> 5) * yap; - - for(j = (1 << 14) - yap; j > Cy; j -= Cy){ - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - } - - r += (rx >> 5) * Cy; - g += (gx >> 5) * Cy; - b += (bx >> 5) * Cy; - } - if(j > 0){ - pix = sptr; - sptr += sow; - rx = R_VAL(pix) * xap; - gx = G_VAL(pix) * xap; - bx = B_VAL(pix) * xap; - pix++; - for(i = (1 << 14) - xap; i > Cx; i -= Cx){ - rx += R_VAL(pix) * Cx; - gx += G_VAL(pix) * Cx; - bx += B_VAL(pix) * Cx; - pix++; - } - if(i > 0){ - rx += R_VAL(pix) * i; - gx += G_VAL(pix) * i; - bx += B_VAL(pix) * i; - } - - r += (rx >> 5) * j; - g += (gx >> 5) * j; - b += (bx >> 5) * j; - } - - *dptr = qRgb(r >> 23, g >> 23, b >> 23); - dptr++; + else { +#ifdef QT_COMPILER_SUPPORTS_SSE4_1 + if (qCpuHasFeature(SSE4_1)) + qt_qimageScaleAARGBA_down_xy_sse4(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + else +#endif + qt_qimageScaleAARGB_down_xy(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + } +} + + +inline static void qt_qimageScaleAARGB_helper_x(const unsigned int *pix, int xap, int Cx, int &r, int &g, int &b) +{ + r = R_VAL(pix) * xap; + g = G_VAL(pix) * xap; + b = B_VAL(pix) * xap; + int j; + for (j = (1 << 14) - xap; j > Cx; j -= Cx ){ + pix++; + r += R_VAL(pix) * Cx; + g += G_VAL(pix) * Cx; + b += B_VAL(pix) * Cx; + } + pix++; + r += R_VAL(pix) * j; + g += G_VAL(pix) * j; + b += B_VAL(pix) * j; +} + +inline static void qt_qimageScaleAARGB_helper_y(const unsigned int *pix, int yap, int Cy, int sow, int &r, int &g, int &b) +{ + r = R_VAL(pix) * yap; + g = G_VAL(pix) * yap; + b = B_VAL(pix) * yap; + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy ){ + pix += sow; + r += R_VAL(pix) * Cy; + g += G_VAL(pix) * Cy; + b += B_VAL(pix) * Cy; + } + pix += sow; + r += R_VAL(pix) * j; + g += G_VAL(pix) * j; + b += B_VAL(pix) * j; +} + +static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int r, g, b; + qt_qimageScaleAARGB_helper_y(sptr, yap, Cy, sow, r, g, b); + + int xap = xapoints[x]; + if (xap > 0) { + int rr, bb, gg; + qt_qimageScaleAARGB_helper_y(sptr + 1, yap, Cy, sow, rr, gg, bb); + + r = r * (256 - xap); + g = g * (256 - xap); + b = b * (256 - xap); + r = (r + (rr * xap)) >> 8; + g = (g + (gg * xap)) >> 8; + b = (b + (bb * xap)) >> 8; } + *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); } } } -#if 0 -static void qt_qimageScaleAARGBASetup(QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow) +static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) { - qInitDrawhelperAsm(); - qt_qimageScaleAARGBA(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int r, g, b; + qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, r, g, b); + + int yap = yapoints[dyy + y]; + if (yap > 0) { + int rr, bb, gg; + qt_qimageScaleAARGB_helper_x(sptr + sow, xap, Cx, rr, gg, bb); + + r = r * (256 - yap); + g = g * (256 - yap); + b = b * (256 - yap); + r = (r + (rr * yap)) >> 8; + g = (g + (gg * yap)) >> 8; + b = (b + (bb * yap)) >> 8; + } + *dptr++ = qRgb(r >> 14, g >> 14, b >> 14); + } + } } -static void qt_qimageScaleAARGBSetup(QImageScaleInfo *isi, unsigned int *dest, - int dxx, int dyy, int dx, int dy, int dw, - int dh, int dow, int sow) +static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, int dw, + int dh, int dow, int sow) { - qInitDrawhelperAsm(); - qt_qimageScaleAARGB(isi, dest, dxx, dyy, dx, dy, dw, dh, dow, sow); + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + int rx, gx, bx; + qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, rx, gx, bx); + + int r = (rx >> 4) * yap; + int g = (gx >> 4) * yap; + int b = (bx >> 4) * yap; + + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, rx, gx, bx); + + r += (rx >> 4) * Cy; + g += (gx >> 4) * Cy; + b += (bx >> 4) * Cy; + } + sptr += sow; + qt_qimageScaleAARGB_helper_x(sptr, xap, Cx, rx, gx, bx); + + r += (rx >> 4) * j; + g += (gx >> 4) * j; + b += (bx >> 4) * j; + + *dptr = qRgb(r >> 24, g >> 24, b >> 24); + dptr++; + } + } } -#endif QImage qSmoothScaleImage(const QImage &src, int dw, int dh) { @@ -1012,7 +793,7 @@ QImage qSmoothScaleImage(const QImage &src, int dw, int dh) return QImage(); } - if (src.format() == QImage::Format_ARGB32_Premultiplied || src.format() == QImage::Format_RGBA8888_Premultiplied) + if (src.hasAlphaChannel()) qt_qimageScaleArgb(scaleinfo, (unsigned int *)buffer.scanLine(0), 0, 0, 0, 0, dw, dh, dw, src.bytesPerLine() / 4); else diff --git a/src/gui/painting/qimagescale_p.h b/src/gui/painting/qimagescale_p.h index 512ec6488e..c35aea451a 100644 --- a/src/gui/painting/qimagescale_p.h +++ b/src/gui/painting/qimagescale_p.h @@ -53,6 +53,15 @@ QT_BEGIN_NAMESPACE */ QImage qSmoothScaleImage(const QImage &img, int w, int h); +namespace QImageScale { + struct QImageScaleInfo { + int *xpoints; + const unsigned int **ypoints; + int *xapoints, *yapoints; + int xup_yup; + }; +} + QT_END_NAMESPACE #endif diff --git a/src/gui/painting/qimagescale_sse4.cpp b/src/gui/painting/qimagescale_sse4.cpp new file mode 100644 index 0000000000..565ea4daa1 --- /dev/null +++ b/src/gui/painting/qimagescale_sse4.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qimagescale_p.h" +#include "qimage.h" +#include + +#if defined(QT_COMPILER_SUPPORTS_SSE4_1) + +QT_BEGIN_NAMESPACE + +using namespace QImageScale; + +inline static __m128i qt_qimageScaleAARGBA_helper_x(const unsigned int *pix, int xap, int Cx, const __m128i vxap, const __m128i vCx) +{ + __m128i vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + __m128i vx = _mm_mullo_epi32(vpix, vxap); + int i; + for (i = (1 << 14) - xap; i > Cx; i -= Cx) { + pix++; + vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, vCx)); + } + pix++; + vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, _mm_set1_epi32(i))); + return vx; +} + +inline static __m128i qt_qimageScaleAARGBA_helper_y(const unsigned int *pix, int yap, int Cy, int sow, const __m128i vyap, const __m128i vCy) +{ + __m128i vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + __m128i vx = _mm_mullo_epi32(vpix, vyap); + int i; + for (i = (1 << 14) - yap; i > Cy; i -= Cy) { + pix += sow; + vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, vCy)); + } + pix += sow; + vpix = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(*pix)); + vx = _mm_add_epi32(vx, _mm_mullo_epi32(vpix, _mm_set1_epi32(i))); + return vx; +} + +template +void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + const __m128i v256 = _mm_set1_epi32(256); + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + const __m128i vCy = _mm_set1_epi32(Cy); + const __m128i vyap = _mm_set1_epi32(yap); + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + __m128i vx = qt_qimageScaleAARGBA_helper_y(sptr, yap, Cy, sow, vyap, vCy); + + int xap = xapoints[x]; + if (xap > 0) { + const __m128i vxap = _mm_set1_epi32(xap); + const __m128i vinvxap = _mm_sub_epi32(v256, vxap); + __m128i vr = qt_qimageScaleAARGBA_helper_y(sptr + 1, yap, Cy, sow, vyap, vCy); + + vx = _mm_mullo_epi32(vx, vinvxap); + vr = _mm_mullo_epi32(vr, vxap); + vx = _mm_add_epi32(vx, vr); + vx = _mm_srli_epi32(vx, 8); + } + vx = _mm_srli_epi32(vx, 14); + vx = _mm_packus_epi32(vx, _mm_setzero_si128()); + vx = _mm_packus_epi16(vx, _mm_setzero_si128()); + *dptr = _mm_cvtsi128_si32(vx); + if (RGB) + *dptr |= 0xff000000; + dptr++; + } + } +} + +template +void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + int end = dxx + dw; + + const __m128i v256 = _mm_set1_epi32(256); + + /* go through every scanline in the output buffer */ + for (int y = 0; y < dh; y++) { + unsigned int *dptr = dest + dx + ((y + dy) * dow); + for (int x = dxx; x < end; x++) { + int Cx = xapoints[x] >> 16; + int xap = xapoints[x] & 0xffff; + const __m128i vCx = _mm_set1_epi32(Cx); + const __m128i vxap = _mm_set1_epi32(xap); + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + __m128i vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + + int yap = yapoints[dyy + y]; + if (yap > 0) { + const __m128i vyap = _mm_set1_epi32(yap); + const __m128i vinvyap = _mm_sub_epi32(v256, vyap); + __m128i vr = qt_qimageScaleAARGBA_helper_x(sptr + sow, xap, Cx, vxap, vCx); + + vx = _mm_mullo_epi32(vx, vinvyap); + vr = _mm_mullo_epi32(vr, vyap); + vx = _mm_add_epi32(vx, vr); + vx = _mm_srli_epi32(vx, 8); + } + vx = _mm_srli_epi32(vx, 14); + vx = _mm_packus_epi32(vx, _mm_setzero_si128()); + vx = _mm_packus_epi16(vx, _mm_setzero_si128()); + *dptr = _mm_cvtsi128_si32(vx); + if (RGB) + *dptr |= 0xff000000; + dptr++; + } + } +} + +template +void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow) +{ + const unsigned int **ypoints = isi->ypoints; + int *xpoints = isi->xpoints; + int *xapoints = isi->xapoints; + int *yapoints = isi->yapoints; + + for (int y = 0; y < dh; y++) { + int Cy = (yapoints[dyy + y]) >> 16; + int yap = (yapoints[dyy + y]) & 0xffff; + const __m128i vCy = _mm_set1_epi32(Cy); + const __m128i vyap = _mm_set1_epi32(yap); + + unsigned int *dptr = dest + dx + ((y + dy) * dow); + int end = dxx + dw; + for (int x = dxx; x < end; x++) { + const int Cx = xapoints[x] >> 16; + const int xap = xapoints[x] & 0xffff; + const __m128i vCx = _mm_set1_epi32(Cx); + const __m128i vxap = _mm_set1_epi32(xap); + + const unsigned int *sptr = ypoints[dyy + y] + xpoints[x]; + __m128i vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + __m128i vr = _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vyap); + + int j; + for (j = (1 << 14) - yap; j > Cy; j -= Cy) { + sptr += sow; + vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vCy)); + } + sptr += sow; + vx = qt_qimageScaleAARGBA_helper_x(sptr, xap, Cx, vxap, vCx); + vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), _mm_set1_epi32(j))); + + vr = _mm_srli_epi32(vr, 24); + vr = _mm_packus_epi32(vr, _mm_setzero_si128()); + vr = _mm_packus_epi16(vr, _mm_setzero_si128()); + *dptr = _mm_cvtsi128_si32(vr); + if (RGB) + *dptr |= 0xff000000; + dptr++; + } + } +} + +template void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +template void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest, + int dxx, int dyy, int dx, int dy, + int dw, int dh, int dow, int sow); + +QT_END_NAMESPACE + +#endif -- cgit v1.2.3 From 95f694682e762dd6860213dbf26fddaebc637da8 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 13 Apr 2015 18:27:49 +0200 Subject: Implement radial and conical gradients for rgb64 rendering Adds the last two missing source types to rgb64 rendering. Conical and radial gradients. At the same time linear gradients are moved to a template form to increase code sharing. Change-Id: I30fdd0837b0da03e3447683856ebbe4d7f48df6c Reviewed-by: Gunnar Sletta --- src/gui/painting/qdrawhelper.cpp | 192 ++++++++++++++++++---------------- src/gui/painting/qdrawhelper_neon.cpp | 2 +- src/gui/painting/qdrawhelper_p.h | 25 +++-- src/gui/painting/qdrawhelper_sse2.cpp | 2 +- 4 files changed, 120 insertions(+), 101 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index aad904e8fc..138e1ecb3b 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -3441,78 +3441,50 @@ static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const Q } } -static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) +class GradientBase32 { - const uint *b = buffer; - qreal t, inc; - - bool affine = true; - qreal rx=0, ry=0; - if (op->linear.l == 0) { - t = inc = 0; - } else { - rx = data->m21 * (y + qreal(0.5)) + data->m11 * (x + qreal(0.5)) + data->dx; - ry = data->m22 * (y + qreal(0.5)) + data->m12 * (x + qreal(0.5)) + data->dy; - t = op->linear.dx*rx + op->linear.dy*ry + op->linear.off; - inc = op->linear.dx * data->m11 + op->linear.dy * data->m12; - affine = !data->m13 && !data->m23; - - if (affine) { - t *= (GRADIENT_STOPTABLE_SIZE - 1); - inc *= (GRADIENT_STOPTABLE_SIZE - 1); - } +public: + typedef uint Type; + static Type null() { return 0; } + static Type fetchSingle(const QGradientData& gradient, qreal v) + { + return qt_gradient_pixel(&gradient, v); } - - const uint *end = buffer + length; - if (affine) { - if (inc > qreal(-1e-5) && inc < qreal(1e-5)) { - QT_MEMFILL_UINT(buffer, length, qt_gradient_pixel_fixed(&data->gradient, int(t * FIXPT_SIZE))); - } else { - if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) && - t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) { - // we can use fixed point math - int t_fixed = int(t * FIXPT_SIZE); - int inc_fixed = int(inc * FIXPT_SIZE); - while (buffer < end) { - *buffer = qt_gradient_pixel_fixed(&data->gradient, t_fixed); - t_fixed += inc_fixed; - ++buffer; - } - } else { - // we have to fall back to float math - while (buffer < end) { - *buffer = qt_gradient_pixel(&data->gradient, t/GRADIENT_STOPTABLE_SIZE); - t += inc; - ++buffer; - } - } - } - } else { // fall back to float math here as well - qreal rw = data->m23 * (y + qreal(0.5)) + data->m13 * (x + qreal(0.5)) + data->m33; - while (buffer < end) { - qreal x = rx/rw; - qreal y = ry/rw; - t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off; - - *buffer = qt_gradient_pixel(&data->gradient, t); - rx += data->m11; - ry += data->m12; - rw += data->m13; - if (!rw) { - rw += data->m13; - } - ++buffer; - } + static Type fetchSingle(const QGradientData& gradient, int v) + { + return qt_gradient_pixel_fixed(&gradient, v); } + static void memfill(Type *buffer, Type fill, int length) + { + qt_memfill32(buffer, fill, length); + } +}; - return b; -} +class GradientBase64 +{ +public: + typedef QRgba64 Type; + static Type null() { return QRgba64::fromRgba64(0); } + static Type fetchSingle(const QGradientData& gradient, qreal v) + { + return qt_gradient_pixel64(&gradient, v); + } + static Type fetchSingle(const QGradientData& gradient, int v) + { + return qt_gradient_pixel64_fixed(&gradient, v); + } + static void memfill(Type *buffer, Type fill, int length) + { + qt_memfill64((quint64*)buffer, fill, length); + } +}; -static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) +template +static inline const BlendType * QT_FASTCALL qt_fetch_linear_gradient_template( + BlendType *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) { - const QRgba64 *b = buffer; + const BlendType *b = buffer; qreal t, inc; bool affine = true; @@ -3532,11 +3504,10 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe } } - const QRgba64 *end = buffer + length; + const BlendType *end = buffer + length; if (affine) { if (inc > qreal(-1e-5) && inc < qreal(1e-5)) { - QRgba64 color = qt_gradient_pixel64_fixed(&data->gradient, int(t * FIXPT_SIZE)); - qt_memfill64((quint64*)buffer, color, length); + GradientBase::memfill(buffer, GradientBase::fetchSingle(data->gradient, int(t * FIXPT_SIZE)), length); } else { if (t+inc*length < qreal(INT_MAX >> (FIXPT_BITS + 1)) && t+inc*length > qreal(INT_MIN >> (FIXPT_BITS + 1))) { @@ -3544,14 +3515,14 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe int t_fixed = int(t * FIXPT_SIZE); int inc_fixed = int(inc * FIXPT_SIZE); while (buffer < end) { - *buffer = qt_gradient_pixel64_fixed(&data->gradient, t_fixed); + *buffer = GradientBase::fetchSingle(data->gradient, t_fixed); t_fixed += inc_fixed; ++buffer; } } else { // we have to fall back to float math while (buffer < end) { - *buffer = qt_gradient_pixel64(&data->gradient, t/GRADIENT_STOPTABLE_SIZE); + *buffer = GradientBase::fetchSingle(data->gradient, t/GRADIENT_STOPTABLE_SIZE); t += inc; ++buffer; } @@ -3564,7 +3535,7 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe qreal y = ry/rw; t = (op->linear.dx*x + op->linear.dy *y) + op->linear.off; - *buffer = qt_gradient_pixel64(&data->gradient, t); + *buffer = GradientBase::fetchSingle(data->gradient, t); rx += data->m11; ry += data->m12; rw += data->m13; @@ -3578,6 +3549,18 @@ static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffe return b; } +static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_linear_gradient_template(buffer, op, data, y, x, length); +} + +static const QRgba64 * QT_FASTCALL qt_fetch_linear_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_linear_gradient_template(buffer, op, data, y, x, length); +} + static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data) { v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x; @@ -3592,19 +3575,22 @@ static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const Q v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0; } -class RadialFetchPlain +template +class RadialFetchPlain : public GradientBase { public: - static inline void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det, - qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) + typedef typename GradientBase::Type BlendType; + static void fetch(BlendType *buffer, BlendType *end, + const Operator *op, const QSpanData *data, qreal det, + qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) { if (op->radial.extended) { while (buffer < end) { - quint32 result = 0; + BlendType result = GradientBase::null(); if (det >= 0) { qreal w = qSqrt(det) - b; if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0) - result = qt_gradient_pixel(&data->gradient, w); + result = GradientBase::fetchSingle(data->gradient, w); } *buffer = result; @@ -3617,7 +3603,7 @@ public: } } else { while (buffer < end) { - *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b); + *buffer++ = GradientBase::fetchSingle(data->gradient, qSqrt(det) - b); det += delta_det; delta_det += delta_delta_det; @@ -3630,15 +3616,23 @@ public: const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { - return qt_fetch_radial_gradient_template(buffer, op, data, y, x, length); + return qt_fetch_radial_gradient_template, uint>(buffer, op, data, y, x, length); } static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain; -static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data, - int y, int x, int length) +const QRgba64 * QT_FASTCALL qt_fetch_radial_gradient_rgb64(QRgba64 *buffer, const Operator *op, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_radial_gradient_template, QRgba64>(buffer, op, data, y, x, length); +} + +template +static inline const BlendType * QT_FASTCALL qt_fetch_conical_gradient_template( + BlendType *buffer, const QSpanData *data, + int y, int x, int length) { - const uint *b = buffer; + const BlendType *b = buffer; qreal rx = data->m21 * (y + qreal(0.5)) + data->dx + data->m11 * (x + qreal(0.5)); qreal ry = data->m22 * (y + qreal(0.5)) @@ -3647,14 +3641,14 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op const qreal inv2pi = M_1_PI / 2.0; - const uint *end = buffer + length; + const BlendType *end = buffer + length; if (affine) { rx -= data->gradient.conical.center.x; ry -= data->gradient.conical.center.y; while (buffer < end) { qreal angle = qAtan2(ry, rx) + data->gradient.conical.angle; - *buffer = qt_gradient_pixel(&data->gradient, 1 - angle * inv2pi); + *buffer = GradientBase::fetchSingle(data->gradient, 1 - angle * inv2pi); rx += data->m11; ry += data->m12; @@ -3670,7 +3664,7 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op rx/rw - data->gradient.conical.center.y) + data->gradient.conical.angle; - *buffer = qt_gradient_pixel(&data->gradient, 1 - angle * inv2pi); + *buffer = GradientBase::fetchSingle(data->gradient, 1 - angle * inv2pi); rx += data->m11; ry += data->m12; @@ -3684,6 +3678,18 @@ static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Op return b; } +static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_conical_gradient_template(buffer, data, y, x, length); +} + +static const QRgba64 * QT_FASTCALL qt_fetch_conical_gradient_rgb64(QRgba64 *buffer, const Operator *, const QSpanData *data, + int y, int x, int length) +{ + return qt_fetch_conical_gradient_template(buffer, data, y, x, length); +} + # define PRELOAD_INIT(x) # define PRELOAD_INIT2(x,y) # define PRELOAD_COND(x) @@ -5876,6 +5882,8 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in switch(data->type) { case QSpanData::Solid: solidSource = data->solid.color.isOpaque(); + op.srcFetch = 0; + op.srcFetch64 = 0; break; case QSpanData::LinearGradient: solidSource = !data->gradient.alphaColor; @@ -5887,18 +5895,20 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in solidSource = !data->gradient.alphaColor; getRadialGradientValues(&op.radial, data); op.srcFetch = qt_fetch_radial_gradient; - op.srcFetch64 = 0; //qt_fetch_radial_gradient_rgb64; + op.srcFetch64 = qt_fetch_radial_gradient_rgb64; break; case QSpanData::ConicalGradient: solidSource = !data->gradient.alphaColor; op.srcFetch = qt_fetch_conical_gradient; - op.srcFetch64 = 0; //qt_fetch_conical_gradient_rgb64; + op.srcFetch64 = qt_fetch_conical_gradient_rgb64; break; case QSpanData::Texture: + solidSource = !data->texture.hasAlpha; op.srcFetch = sourceFetch[getBlendType(data)][data->texture.format]; op.srcFetch64 = sourceFetch64[getBlendType(data)][data->texture.format]; - solidSource = !data->texture.hasAlpha; + break; default: + Q_UNREACHABLE(); break; } @@ -6212,7 +6222,7 @@ public: bool isSupported() const { - return op.srcFetch64 && op.func64 && op.destFetch64 && op.destStore64; + return op.func64 && op.destFetch64 && op.destStore64; } const QRgba64 *fetch(int x, int y, int len) @@ -6303,7 +6313,7 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi QSpanData *data = reinterpret_cast(userData); Operator op = getOperator(data, spans, count); - if (!op.srcFetch64 || !op.func64) { + if (!op.func64) { qWarning() << Q_FUNC_INFO << "Unsupported blend"; return blend_untransformed_generic(count, spans, userData); } @@ -6544,7 +6554,7 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD QSpanData *data = reinterpret_cast(userData); Operator op = getOperator(data, spans, count); - if (!op.srcFetch64 || !op.func64) { + if (!op.func64) { qDebug("unsupported rgb64 blend"); return blend_tiled_generic(count, spans, userData); } diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 36e2488a94..08e564f017 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -986,7 +986,7 @@ public: const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { - return qt_fetch_radial_gradient_template >(buffer, op, data, y, x, length); + return qt_fetch_radial_gradient_template,uint>(buffer, op, data, y, x, length); } QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 53f4db6fce..d584e392e9 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -395,24 +395,24 @@ static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c) return (b * b) - (4 * a * c); } -template Q_STATIC_TEMPLATE_FUNCTION -const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const Operator *op, const QSpanData *data, - int y, int x, int length) +template static +const BlendType * QT_FASTCALL qt_fetch_radial_gradient_template(BlendType *buffer, const Operator *op, + const QSpanData *data, int y, int x, int length) { // avoid division by zero if (qFuzzyIsNull(op->radial.a)) { - qt_memfill32(buffer, 0, length); + RadialFetchFunc::memfill(buffer, RadialFetchFunc::null(), length); return buffer; } - const uint *b = buffer; + const BlendType *b = buffer; qreal rx = data->m21 * (y + qreal(0.5)) + data->dx + data->m11 * (x + qreal(0.5)); qreal ry = data->m22 * (y + qreal(0.5)) + data->dy + data->m12 * (x + qreal(0.5)); bool affine = !data->m13 && !data->m23; - uint *end = buffer + length; + BlendType *end = buffer + length; if (affine) { rx -= data->gradient.radial.focal.x; ry -= data->gradient.radial.focal.y; @@ -459,7 +459,7 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + gx*op->radial.dx + gy*op->radial.dy); qreal det = qRadialDeterminant(op->radial.a, b, op->radial.sqrfr - (gx*gx + gy*gy)); - quint32 result = 0; + BlendType result = RadialFetchFunc::null(); if (det >= 0) { qreal detSqrt = qSqrt(det); @@ -469,7 +469,7 @@ const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const O qreal s = qMax(s0, s1); if (data->gradient.radial.focal.radius + op->radial.dr * s >= 0) - result = qt_gradient_pixel(&data->gradient, s); + result = RadialFetchFunc::fetchSingle(data->gradient, s); } *buffer = result; @@ -490,6 +490,15 @@ template class QRadialFetchSimd { public: + static uint null() { return 0; } + static uint fetchSingle(const QGradientData& gradient, qreal v) + { + return qt_gradient_pixel(&gradient, v); + } + static void memfill(uint *buffer, uint fill, int length) + { + qt_memfill32(buffer, fill, length); + } static void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det, qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b) { diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index b8957fe2fb..17e9d462fd 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -550,7 +550,7 @@ public: const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data, int y, int x, int length) { - return qt_fetch_radial_gradient_template >(buffer, op, data, y, x, length); + return qt_fetch_radial_gradient_template,uint>(buffer, op, data, y, x, length); } void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl, -- cgit v1.2.3 From 528279febe74a5e995589d9c5eeb6c533cc2fe7c Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 13 Apr 2015 11:48:00 +0200 Subject: Optimize non-native bilinear transforms Reading directly from an array instead of calling a function pointer is much faster. Change-Id: I833b33448bad064d6f38d2f9ff44138d90206822 Reviewed-by: Gunnar Sletta --- src/gui/painting/qdrawhelper.cpp | 45 +++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index b75018452a..37f2de98b6 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -1931,10 +1931,17 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper int x2; fetchTransformedBilinear_pixelBounds(image_width, image_x1, image_x2, x1, x2); - buf1[i * 2 + 0] = fetch(s1, x1); - buf1[i * 2 + 1] = fetch(s1, x2); - buf2[i * 2 + 0] = fetch(s2, x1); - buf2[i * 2 + 1] = fetch(s2, x2); + if (layout->bpp == QPixelLayout::BPP32) { + buf1[i * 2 + 0] = ((const uint*)s1)[x1]; + buf1[i * 2 + 1] = ((const uint*)s1)[x2]; + buf2[i * 2 + 0] = ((const uint*)s2)[x1]; + buf2[i * 2 + 1] = ((const uint*)s2)[x2]; + } else { + buf1[i * 2 + 0] = fetch(s1, x1); + buf1[i * 2 + 1] = fetch(s1, x2); + buf2[i * 2 + 0] = fetch(s2, x1); + buf2[i * 2 + 1] = fetch(s2, x2); + } fx += fdx; } @@ -1989,10 +1996,17 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper const uchar *s1 = data->texture.scanLine(y1); const uchar *s2 = data->texture.scanLine(y2); - buf1[i * 2 + 0] = fetch(s1, x1); - buf1[i * 2 + 1] = fetch(s1, x2); - buf2[i * 2 + 0] = fetch(s2, x1); - buf2[i * 2 + 1] = fetch(s2, x2); + if (layout->bpp == QPixelLayout::BPP32) { + buf1[i * 2 + 0] = ((const uint*)s1)[x1]; + buf1[i * 2 + 1] = ((const uint*)s1)[x2]; + buf2[i * 2 + 0] = ((const uint*)s2)[x1]; + buf2[i * 2 + 1] = ((const uint*)s2)[x2]; + } else { + buf1[i * 2 + 0] = fetch(s1, x1); + buf1[i * 2 + 1] = fetch(s1, x2); + buf2[i * 2 + 0] = fetch(s2, x1); + buf2[i * 2 + 1] = fetch(s2, x2); + } fx += fdx; fy += fdy; @@ -2074,10 +2088,17 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper const uchar *s1 = data->texture.scanLine(y1); const uchar *s2 = data->texture.scanLine(y2); - buf1[i * 2 + 0] = fetch(s1, x1); - buf1[i * 2 + 1] = fetch(s1, x2); - buf2[i * 2 + 0] = fetch(s2, x1); - buf2[i * 2 + 1] = fetch(s2, x2); + if (layout->bpp == QPixelLayout::BPP32) { + buf1[i * 2 + 0] = ((const uint*)s1)[x1]; + buf1[i * 2 + 1] = ((const uint*)s1)[x2]; + buf2[i * 2 + 0] = ((const uint*)s2)[x1]; + buf2[i * 2 + 1] = ((const uint*)s2)[x2]; + } else { + buf1[i * 2 + 0] = fetch(s1, x1); + buf1[i * 2 + 1] = fetch(s1, x2); + buf2[i * 2 + 0] = fetch(s2, x1); + buf2[i * 2 + 1] = fetch(s2, x2); + } fx += fdx; fy += fdy; -- cgit v1.2.3 From a7303e45dbd1ac37048fb1a907edabe0158b2b52 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 14 Apr 2015 14:41:13 +0200 Subject: Move composition out of qdrawhelper.c Also changes the way the SSE2 composition modes are inserted into the table, so it is handled like all the other tables and doesn't require duplicating most of the table. Change-Id: I8de383caece0367bc7466d7a1b145aa820c3bd6a Reviewed-by: Gunnar Sletta --- src/gui/painting/painting.pri | 1 + src/gui/painting/qcompositionfunctions.cpp | 2197 +++++++++++++++++++++++++++ src/gui/painting/qdrawhelper.cpp | 2238 +--------------------------- src/gui/painting/qdrawhelper_p.h | 80 - src/gui/painting/qdrawhelper_sse2.cpp | 84 -- 5 files changed, 2236 insertions(+), 2364 deletions(-) create mode 100644 src/gui/painting/qcompositionfunctions.cpp (limited to 'src/gui/painting') diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index fafc67cf46..bd98f4ae46 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -60,6 +60,7 @@ SOURCES += \ painting/qbrush.cpp \ painting/qcolor.cpp \ painting/qcolor_p.cpp \ + painting/qcompositionfunctions.cpp \ painting/qcosmeticstroker.cpp \ painting/qcssutil.cpp \ painting/qdrawhelper.cpp \ diff --git a/src/gui/painting/qcompositionfunctions.cpp b/src/gui/painting/qcompositionfunctions.cpp new file mode 100644 index 0000000000..ba428a7938 --- /dev/null +++ b/src/gui/painting/qcompositionfunctions.cpp @@ -0,0 +1,2197 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +# define PRELOAD_INIT(x) +# define PRELOAD_INIT2(x,y) +# define PRELOAD_COND(x) +# define PRELOAD_COND2(x,y) + +/* The constant alpha factor describes an alpha factor that gets applied + to the result of the composition operation combining it with the destination. + + The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1. + we get the unmodified operation + + result = src op dest + dest = result * const_alpha + dest * (1. - const_alpha) + + This means that in the comments below, the first line is the const_alpha==255 case, the + second line the general one. + + In the lines below: + s == src, sa == alpha(src), sia = 1 - alpha(src) + d == dest, da == alpha(dest), dia = 1 - alpha(dest) + ca = const_alpha, cia = 1 - const_alpha + + The methods exist in two variants. One where we have a constant source, the other + where the source is an array of pixels. +*/ + +/* + result = 0 + d = d * cia +*/ +#define comp_func_Clear_impl(dest, length, const_alpha)\ +{\ + if (const_alpha == 255) {\ + QT_MEMFILL_UINT(dest, length, 0);\ + } else {\ + int ialpha = 255 - const_alpha;\ + PRELOAD_INIT(dest)\ + for (int i = 0; i < length; ++i) {\ + PRELOAD_COND(dest)\ + dest[i] = BYTE_MUL(dest[i], ialpha);\ + }\ + }\ +} + +void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha) +{ + comp_func_Clear_impl(dest, length, const_alpha); +} + +void QT_FASTCALL comp_func_solid_Clear_rgb64(QRgba64 *dest, int length, QRgba64, uint const_alpha) +{ + if (const_alpha == 255) + qt_memfill64((quint64*)dest, 0, length); + else { + int ialpha = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha255(dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha) +{ + comp_func_Clear_impl(dest, length, const_alpha); +} + +void QT_FASTCALL comp_func_Clear_rgb64(QRgba64 *dest, const QRgba64 *, int length, uint const_alpha) +{ + if (const_alpha == 255) + qt_memfill64((quint64*)dest, 0, length); + else { + int ialpha = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha255(dest[i], ialpha); + } + } +} + +/* + result = s + dest = s * ca + d * cia +*/ +void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) { + QT_MEMFILL_UINT(dest, length, color); + } else { + int ialpha = 255 - const_alpha; + color = BYTE_MUL(color, const_alpha); + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = color + BYTE_MUL(dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_solid_Source_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) + qt_memfill64((quint64*)dest, color, length); + else { + int ialpha = 255 - const_alpha; + color = multiplyAlpha255(color, const_alpha); + for (int i = 0; i < length; ++i) { + dest[i] = color + multiplyAlpha255(dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_Source(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + ::memcpy(dest, src, length * sizeof(uint)); + } else { + int ialpha = 255 - const_alpha; + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_Source_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + ::memcpy(dest, src, length * sizeof(quint64)); + else { + int ialpha = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + dest[i] = interpolate255(src[i], const_alpha, dest[i], ialpha); + } + } +} + +void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint) +{ +} + +void QT_FASTCALL comp_func_solid_Destination_rgb64(QRgba64 *, int, QRgba64, uint) +{ +} + +void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint) +{ +} + +void QT_FASTCALL comp_func_Destination_rgb64(QRgba64 *, const QRgba64 *, int, uint) +{ +} + +/* + result = s + d * sia + dest = (s + d * sia) * ca + d * cia + = s * ca + d * (sia * ca + cia) + = s * ca + d * (1 - sa*ca) +*/ +void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha) +{ + if ((const_alpha & qAlpha(color)) == 255) { + QT_MEMFILL_UINT(dest, length, color); + } else { + if (const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color)); + } + } +} + +void QT_FASTCALL comp_func_solid_SourceOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255 && color.isOpaque()) { + qt_memfill64((quint64*)dest, color, length); + } else { + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + for (int i = 0; i < length; ++i) { + dest[i] = color + multiplyAlpha65535(dest[i], 65535 - color.alpha()); + } + } +} + +void QT_FASTCALL comp_func_SourceOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = src[i]; + if (s >= 0xff000000) + dest[i] = s; + else if (s != 0) + dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); + } + } else { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = BYTE_MUL(src[i], const_alpha); + dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); + } + } +} + +void QT_FASTCALL comp_func_SourceOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 s = src[i]; + if (s.isOpaque()) + dest[i] = s; + else if (!s.isTransparent()) + dest[i] = s + multiplyAlpha65535(dest[i], 65535 - s.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + dest[i] = s + multiplyAlpha65535(dest[i], 65535 - s.alpha()); + } + } +} + +/* + result = d + s * dia + dest = (d + s * dia) * ca + d * cia + = d + s * dia * ca +*/ +void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = d + BYTE_MUL(color, qAlpha(~d)); + } +} + +void QT_FASTCALL comp_func_solid_DestinationOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = d + multiplyAlpha65535(color, 65535 - d.alpha()); + } +} + +void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + dest[i] = d + BYTE_MUL(src[i], qAlpha(~d)); + } + } else { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = BYTE_MUL(src[i], const_alpha); + dest[i] = d + BYTE_MUL(s, qAlpha(~d)); + } + } +} + +void QT_FASTCALL comp_func_DestinationOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = d + multiplyAlpha65535(src[i], 65535 - d.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + dest[i] = d + multiplyAlpha65535(s, 65535 - d.alpha()); + } + } +} + +/* + result = s * da + dest = s * da * ca + d * cia +*/ +void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha) +{ + PRELOAD_INIT(dest) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = BYTE_MUL(color, qAlpha(dest[i])); + } + } else { + color = BYTE_MUL(color, const_alpha); + uint cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia); + } + } +} + +void QT_FASTCALL comp_func_solid_SourceIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(color, dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + color = multiplyAlpha65535(color, ca); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(color, d.alpha(), d, cia); + } + } +} + +void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = BYTE_MUL(src[i], qAlpha(dest[i])); + } + } else { + uint cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = BYTE_MUL(src[i], const_alpha); + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia); + } + } +} + +void QT_FASTCALL comp_func_SourceIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(src[i], dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha65535(src[i], ca); + dest[i] = interpolate65535(s, d.alpha(), d, cia); + } + } +} + +/* + result = d * sa + dest = d * sa * ca + d * cia + = d * (sa * ca + cia) +*/ +void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha) +{ + uint a = qAlpha(color); + if (const_alpha != 255) { + a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; + } + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = BYTE_MUL(dest[i], a); + } +} + +void QT_FASTCALL comp_func_solid_DestinationIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + uint a = color.alpha(); + uint ca64k = const_alpha * 257; + if (const_alpha != 255) + a = qt_div_65535(a * ca64k) + 65535 - ca64k; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], a); + } +} + +void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = BYTE_MUL(dest[i], qAlpha(src[i])); + } + } else { + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia; + dest[i] = BYTE_MUL(dest[i], a); + } + } +} + +void QT_FASTCALL comp_func_DestinationIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], src[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + uint a = qt_div_65535(src[i].alpha() * ca) + cia; + dest[i] = multiplyAlpha65535(dest[i], a); + } + } +} + +/* + result = s * dia + dest = s * dia * ca + d * cia +*/ + +void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha) +{ + PRELOAD_INIT(dest) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = BYTE_MUL(color, qAlpha(~dest[i])); + } + } else { + color = BYTE_MUL(color, const_alpha); + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia); + } + } +} + +void QT_FASTCALL comp_func_solid_SourceOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(color, 65535 - dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + color = multiplyAlpha65535(color, ca); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(color, 65535 - d.alpha(), d, cia); + } + } +} + +void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i])); + } + } else { + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = BYTE_MUL(src[i], const_alpha); + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia); + } + } +} + +void QT_FASTCALL comp_func_SourceOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(src[i], 65535 - dest[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha65535(src[i], ca); + dest[i] = interpolate65535(s, 65535 - d.alpha(), d, cia); + } + } +} + +/* + result = d * sia + dest = d * sia * ca + d * cia + = d * (sia * ca + cia) +*/ +void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha) +{ + uint a = qAlpha(~color); + if (const_alpha != 255) + a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = BYTE_MUL(dest[i], a); + } +} + +void QT_FASTCALL comp_func_solid_DestinationOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + uint a = 65535 - color.alpha(); + uint ca64k = const_alpha * 257; + if (const_alpha != 255) + a = qt_div_65535(a * ca64k) + 65535 - ca64k; + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], a); + } +} + +void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i])); + } + } else { + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia; + dest[i] = BYTE_MUL(dest[i], sia); + } + } +} + +void QT_FASTCALL comp_func_DestinationOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = multiplyAlpha65535(dest[i], 65535 - src[i].alpha()); + } + } else { + uint ca = const_alpha * 257; + uint cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + uint a = qt_div_65535((65535 - src[i].alpha()) * ca) + cia; + dest[i] = multiplyAlpha65535(dest[i], a); + } + } +} + +/* + result = s*da + d*sia + dest = s*da*ca + d*sia*ca + d *cia + = s*ca * da + d * (sia*ca + cia) + = s*ca * da + d * (1 - sa*ca) +*/ +void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha != 255) { + color = BYTE_MUL(color, const_alpha); + } + uint sia = qAlpha(~color); + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia); + } +} + +void QT_FASTCALL comp_func_solid_SourceAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + uint sia = 65535 - color.alpha(); + for (int i = 0; i < length; ++i) { + dest[i] = interpolate65535(color, dest[i].alpha(), dest[i], sia); + } +} + +void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = src[i]; + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); + } + } else { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = BYTE_MUL(src[i], const_alpha); + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); + } + } +} + +void QT_FASTCALL comp_func_SourceAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 s = src[i]; + QRgba64 d = dest[i]; + dest[i] = interpolate65535(s, d.alpha(), d, 65535 - s.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + QRgba64 d = dest[i]; + dest[i] = interpolate65535(s, d.alpha(), d, 65535 - s.alpha()); + } + } +} + +/* + result = d*sa + s*dia + dest = d*sa*ca + s*dia*ca + d *cia + = s*ca * dia + d * (sa*ca + cia) +*/ +void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha) +{ + uint a = qAlpha(color); + if (const_alpha != 255) { + color = BYTE_MUL(color, const_alpha); + a = qAlpha(color) + 255 - const_alpha; + } + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d)); + } +} + +void QT_FASTCALL comp_func_solid_DestinationAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + uint a = color.alpha(); + if (const_alpha != 255) { + color = multiplyAlpha255(color, const_alpha); + a = color.alpha() + 65535 - (const_alpha * 257); + } + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(d, a, color, 65535 - d.alpha()); + } +} + +void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = src[i]; + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d)); + } + } else { + int cia = 255 - const_alpha; + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint s = BYTE_MUL(src[i], const_alpha); + uint d = dest[i]; + uint a = qAlpha(s) + cia; + dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d)); + } + } +} + +void QT_FASTCALL comp_func_DestinationAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 s = src[i]; + QRgba64 d = dest[i]; + dest[i] = interpolate65535(d, s.alpha(), s, 65535 - d.alpha()); + } + } else { + int ca = const_alpha * 257; + int cia = 65535 - ca; + for (int i = 0; i < length; ++i) { + QRgba64 s = multiplyAlpha65535(src[i], ca); + QRgba64 d = dest[i]; + uint a = s.alpha() + cia; + dest[i] = interpolate65535(d, a, s, 65535 - d.alpha()); + } + } +} + +/* + result = d*sia + s*dia + dest = d*sia*ca + s*dia*ca + d *cia + = s*ca * dia + d * (sia*ca + cia) + = s*ca * dia + d * (1 - sa*ca) +*/ +void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha != 255) + color = BYTE_MUL(color, const_alpha); + uint sia = qAlpha(~color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia); + } +} + +void QT_FASTCALL comp_func_solid_XOR_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha != 255) + color = multiplyAlpha255(color, const_alpha); + uint sia = 65535 - color.alpha(); + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + dest[i] = interpolate65535(color, 65535 - d.alpha(), d, sia); + } +} + +void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + PRELOAD_INIT2(dest, src) + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); + } + } else { + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = BYTE_MUL(src[i], const_alpha); + dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); + } + } +} + +void QT_FASTCALL comp_func_XOR_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = src[i]; + dest[i] = interpolate65535(s, 65535 - d.alpha(), d, 65535 - s.alpha()); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + QRgba64 s = multiplyAlpha255(src[i], const_alpha); + dest[i] = interpolate65535(s, 65535 - d.alpha(), d, 65535 - s.alpha()); + } + } +} + +struct QFullCoverage { + inline void store(uint *dest, const uint src) const + { + *dest = src; + } +}; + +struct QPartialCoverage { + inline QPartialCoverage(uint const_alpha) + : ca(const_alpha) + , ica(255 - const_alpha) + { + } + + inline void store(uint *dest, const uint src) const + { + *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica); + } + +private: + const uint ca; + const uint ica; +}; + +static inline int mix_alpha(int da, int sa) +{ + return 255 - ((255 - sa) * (255 - da) >> 8); +} + +/* + Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa) + = Sca + Dca +*/ +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage) +{ + uint s = color; + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + d = comp_func_Plus_one_pixel(d, s); + coverage.store(&dest[i], d); + } +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl_rgb64(QRgba64 *dest, int length, QRgba64 color, const T &coverage) +{ + QRgba64 s = color; + for (int i = 0; i < length; ++i) { + QRgba64 d = dest[i]; + d = comp_func_Plus_one_pixel(d, s); + coverage.store(&dest[i], d); + } +} + +void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Plus_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +void QT_FASTCALL comp_func_solid_Plus_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = addWithSaturation(dest[i], color); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = addWithSaturation(dest[i], color); + dest[i] = interpolate255(d, const_alpha, dest[i], 255 - const_alpha); + } + } +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + d = comp_func_Plus_one_pixel(d, s); + + coverage.store(&dest[i], d); + } +} + +void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Plus_impl(dest, src, length, QFullCoverage()); + else + comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +void QT_FASTCALL comp_func_Plus_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) { + for (int i = 0; i < length; ++i) { + dest[i] = addWithSaturation(dest[i], src[i]); + } + } else { + for (int i = 0; i < length; ++i) { + QRgba64 d = addWithSaturation(dest[i], src[i]); + dest[i] = interpolate255(d, const_alpha, dest[i], 255 - const_alpha); + } + } +} + +/* + Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int multiply_op(int dst, int src, int da, int sa) +{ + return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) multiply_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) multiply_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Multiply(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Multiply_impl(dest, src, length, QFullCoverage()); + else + comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) + = Sca + Dca - Sca.Dca +*/ +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) 255 - qt_div_255((255-a) * (255-b)) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Screen_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) 255 - (((255-a) * (255-b)) >> 8) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Screen_impl(dest, src, length, QFullCoverage()); + else + comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if 2.Dca < Da + Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise + Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int overlay_op(int dst, int src, int da, int sa) +{ + const int temp = src * (255 - da) + dst * (255 - sa); + if (2 * dst < da) + return qt_div_255(2 * src * dst + temp); + else + return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) overlay_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) overlay_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Overlay(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Overlay_impl(dest, src, length, QFullCoverage()); + else + comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) + Da' = Sa + Da - Sa.Da +*/ +static inline int darken_op(int dst, int src, int da, int sa) +{ + return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) darken_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Darken_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) darken_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Darken(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Darken_impl(dest, src, length, QFullCoverage()); + else + comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) + Da' = Sa + Da - Sa.Da +*/ +static inline int lighten_op(int dst, int src, int da, int sa) +{ + return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) lighten_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) lighten_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Lighten(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Lighten_impl(dest, src, length, QFullCoverage()); + else + comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if Sca.Da + Dca.Sa >= Sa.Da + Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise + Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int color_dodge_op(int dst, int src, int da, int sa) +{ + const int sa_da = sa * da; + const int dst_sa = dst * sa; + const int src_da = src * da; + + const int temp = src * (255 - da) + dst * (255 - sa); + if (src_da + dst_sa >= sa_da) + return qt_div_255(sa_da + temp); + else + return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a,b) color_dodge_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) color_dodge_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_ColorDodge(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_ColorDodge_impl(dest, src, length, QFullCoverage()); + else + comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if Sca.Da + Dca.Sa <= Sa.Da + Dca' = Sca.(1 - Da) + Dca.(1 - Sa) + otherwise + Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int color_burn_op(int dst, int src, int da, int sa) +{ + const int src_da = src * da; + const int dst_sa = dst * sa; + const int sa_da = sa * da; + + const int temp = src * (255 - da) + dst * (255 - sa); + + if (src == 0 || src_da + dst_sa <= sa_da) + return qt_div_255(temp); + return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) color_burn_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) color_burn_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_ColorBurn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_ColorBurn_impl(dest, src, length, QFullCoverage()); + else + comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if 2.Sca < Sa + Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise + Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline uint hardlight_op(int dst, int src, int da, int sa) +{ + const uint temp = src * (255 - da) + dst * (255 - sa); + + if (2 * src < sa) + return qt_div_255(2 * src * dst + temp); + else + return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) hardlight_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) hardlight_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_HardLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_HardLight_impl(dest, src, length, QFullCoverage()); + else + comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + if 2.Sca <= Sa + Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise if 2.Sca > Sa and 4.Dca <= Da + Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) + otherwise if 2.Sca > Sa and 4.Dca > Da + Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +static inline int soft_light_op(int dst, int src, int da, int sa) +{ + const int src2 = src << 1; + const int dst_np = da != 0 ? (255 * dst) / da : 0; + const int temp = (src * (255 - da) + dst * (255 - sa)) * 255; + + if (src2 < sa) + return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025; + else if (4 * dst <= da) + return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025; + else { + return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025; + } +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) soft_light_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) soft_light_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_SoftLight_impl(dest, src, length, QFullCoverage()); + else + comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa) + = Sca + Dca - 2.min(Sca.Da, Dca.Sa) +*/ +static inline int difference_op(int dst, int src, int da, int sa) +{ + return src + dst - qt_div_255(2 * qMin(src * da, dst * sa)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) difference_op(a, b, da, sa) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Difference_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) difference_op(a, b, da, sa) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Difference(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Difference_impl(dest, src, length, QFullCoverage()); + else + comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +/* + Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) +*/ +template +Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage) +{ + int sa = qAlpha(color); + int sr = qRed(color); + int sg = qGreen(color); + int sb = qBlue(color); + + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) + uint d = dest[i]; + int da = qAlpha(d); + +#define OP(a, b) (a + b - qt_div_255(2*(a*b))) + int r = OP( qRed(d), sr); + int b = OP( qBlue(d), sb); + int g = OP(qGreen(d), sg); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage()); + else + comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha)); +} + +template +Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) +{ + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) + uint d = dest[i]; + uint s = src[i]; + + int da = qAlpha(d); + int sa = qAlpha(s); + +#define OP(a, b) (a + b - ((a*b) >> 7)) + int r = OP( qRed(d), qRed(s)); + int b = OP( qBlue(d), qBlue(s)); + int g = OP(qGreen(d), qGreen(s)); + int a = mix_alpha(da, sa); +#undef OP + + coverage.store(&dest[i], qRgba(r, g, b, a)); + } +} + +void QT_FASTCALL comp_func_Exclusion(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) +{ + if (const_alpha == 255) + comp_func_Exclusion_impl(dest, src, length, QFullCoverage()); + else + comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha)); +} + +void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) + *dest++ |= color; +} + +void QT_FASTCALL rasterop_SourceOrDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) + *dest++ |= *src++; +} + +void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color |= 0xff000000; + while (length--) + *dest++ &= color; +} + +void QT_FASTCALL rasterop_SourceAndDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (*src & *dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color &= 0x00ffffff; + while (length--) + *dest++ ^= color; +} + +void QT_FASTCALL rasterop_SourceXorDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (*src ^ *dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color; + while (length--) { + *dest = (color & ~(*dest)) | 0xff000000; + ++dest; + } +} + +void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (~(*src) & ~(*dest)) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color | 0xff000000; + while (length--) { + *dest = color | ~(*dest); + ++dest; + } +} + +void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = ~(*src) | ~(*dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color & 0x00ffffff; + while (length--) { + *dest = color ^ (*dest); + ++dest; + } +} + +void QT_FASTCALL rasterop_NotSourceXorDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = ((~(*src)) ^ (*dest)) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length, + uint color, uint const_alpha) +{ + Q_UNUSED(const_alpha); + qt_memfill(dest, ~color | 0xff000000, length); +} + +void QT_FASTCALL rasterop_NotSource(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, + int length, uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) + *dest++ = ~(*src++) | 0xff000000; +} + +void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color | 0xff000000; + while (length--) { + *dest = color & *dest; + ++dest; + } +} + +void QT_FASTCALL rasterop_NotSourceAndDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (~(*src) & *dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (color & ~(*dest)) | 0xff000000; + ++dest; + } +} + +void QT_FASTCALL rasterop_SourceAndNotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (*src & ~(*dest)) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_NotSourceOrDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (~(*src) | *dest) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_NotSourceOrDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + color = ~color | 0xff000000; + while (length--) + *dest++ |= color; +} + +void QT_FASTCALL rasterop_SourceOrNotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (*src | ~(*dest)) | 0xff000000; + ++dest; ++src; + } +} + +void QT_FASTCALL rasterop_solid_SourceOrNotDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(const_alpha); + while (length--) { + *dest = (color | ~(*dest)) | 0xff000000; + ++dest; + } +} + +void QT_FASTCALL rasterop_ClearDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(src); + comp_func_solid_SourceOver (dest, length, 0xff000000, const_alpha); +} + +void QT_FASTCALL rasterop_solid_ClearDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(color); + comp_func_solid_SourceOver (dest, length, 0xff000000, const_alpha); +} + +void QT_FASTCALL rasterop_SetDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(src); + comp_func_solid_SourceOver (dest, length, 0xffffffff, const_alpha); +} + +void QT_FASTCALL rasterop_solid_SetDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(color); + comp_func_solid_SourceOver (dest, length, 0xffffffff, const_alpha); +} + +void QT_FASTCALL rasterop_NotDestination(uint *Q_DECL_RESTRICT dest, + const uint *Q_DECL_RESTRICT src, + int length, + uint const_alpha) +{ + Q_UNUSED(src); + rasterop_solid_SourceXorDestination (dest, length, 0x00ffffff, const_alpha); +} + +void QT_FASTCALL rasterop_solid_NotDestination(uint *Q_DECL_RESTRICT dest, + int length, + uint color, + uint const_alpha) +{ + Q_UNUSED(color); + rasterop_solid_SourceXorDestination (dest, length, 0x00ffffff, const_alpha); +} + +CompositionFunctionSolid qt_functionForModeSolid_C[] = { + comp_func_solid_SourceOver, + comp_func_solid_DestinationOver, + comp_func_solid_Clear, + comp_func_solid_Source, + comp_func_solid_Destination, + comp_func_solid_SourceIn, + comp_func_solid_DestinationIn, + comp_func_solid_SourceOut, + comp_func_solid_DestinationOut, + comp_func_solid_SourceAtop, + comp_func_solid_DestinationAtop, + comp_func_solid_XOR, + comp_func_solid_Plus, + comp_func_solid_Multiply, + comp_func_solid_Screen, + comp_func_solid_Overlay, + comp_func_solid_Darken, + comp_func_solid_Lighten, + comp_func_solid_ColorDodge, + comp_func_solid_ColorBurn, + comp_func_solid_HardLight, + comp_func_solid_SoftLight, + comp_func_solid_Difference, + comp_func_solid_Exclusion, + rasterop_solid_SourceOrDestination, + rasterop_solid_SourceAndDestination, + rasterop_solid_SourceXorDestination, + rasterop_solid_NotSourceAndNotDestination, + rasterop_solid_NotSourceOrNotDestination, + rasterop_solid_NotSourceXorDestination, + rasterop_solid_NotSource, + rasterop_solid_NotSourceAndDestination, + rasterop_solid_SourceAndNotDestination, + rasterop_solid_NotSourceOrDestination, + rasterop_solid_SourceOrNotDestination, + rasterop_solid_ClearDestination, + rasterop_solid_SetDestination, + rasterop_solid_NotDestination +}; + +CompositionFunctionSolid64 qt_functionForModeSolid64_C[] = { + comp_func_solid_SourceOver_rgb64, + comp_func_solid_DestinationOver_rgb64, + comp_func_solid_Clear_rgb64, + comp_func_solid_Source_rgb64, + comp_func_solid_Destination_rgb64, + comp_func_solid_SourceIn_rgb64, + comp_func_solid_DestinationIn_rgb64, + comp_func_solid_SourceOut_rgb64, + comp_func_solid_DestinationOut_rgb64, + comp_func_solid_SourceAtop_rgb64, + comp_func_solid_DestinationAtop_rgb64, + comp_func_solid_XOR_rgb64, + comp_func_solid_Plus_rgb64, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +CompositionFunction qt_functionForMode_C[] = { + comp_func_SourceOver, + comp_func_DestinationOver, + comp_func_Clear, + comp_func_Source, + comp_func_Destination, + comp_func_SourceIn, + comp_func_DestinationIn, + comp_func_SourceOut, + comp_func_DestinationOut, + comp_func_SourceAtop, + comp_func_DestinationAtop, + comp_func_XOR, + comp_func_Plus, + comp_func_Multiply, + comp_func_Screen, + comp_func_Overlay, + comp_func_Darken, + comp_func_Lighten, + comp_func_ColorDodge, + comp_func_ColorBurn, + comp_func_HardLight, + comp_func_SoftLight, + comp_func_Difference, + comp_func_Exclusion, + rasterop_SourceOrDestination, + rasterop_SourceAndDestination, + rasterop_SourceXorDestination, + rasterop_NotSourceAndNotDestination, + rasterop_NotSourceOrNotDestination, + rasterop_NotSourceXorDestination, + rasterop_NotSource, + rasterop_NotSourceAndDestination, + rasterop_SourceAndNotDestination, + rasterop_NotSourceOrDestination, + rasterop_SourceOrNotDestination, + rasterop_ClearDestination, + rasterop_SetDestination, + rasterop_NotDestination +}; + +CompositionFunction64 qt_functionForMode64_C[] = { + comp_func_SourceOver_rgb64, + comp_func_DestinationOver_rgb64, + comp_func_Clear_rgb64, + comp_func_Source_rgb64, + comp_func_Destination_rgb64, + comp_func_SourceIn_rgb64, + comp_func_DestinationIn_rgb64, + comp_func_SourceOut_rgb64, + comp_func_DestinationOut_rgb64, + comp_func_SourceAtop_rgb64, + comp_func_DestinationAtop_rgb64, + comp_func_XOR_rgb64, + comp_func_Plus_rgb64, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 138e1ecb3b..954c4c539a 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -3690,2168 +3690,17 @@ static const QRgba64 * QT_FASTCALL qt_fetch_conical_gradient_rgb64(QRgba64 *buff return qt_fetch_conical_gradient_template(buffer, data, y, x, length); } -# define PRELOAD_INIT(x) -# define PRELOAD_INIT2(x,y) -# define PRELOAD_COND(x) -# define PRELOAD_COND2(x,y) +extern CompositionFunctionSolid qt_functionForModeSolid_C[]; +extern CompositionFunctionSolid64 qt_functionForModeSolid64_C[]; -/* The constant alpha factor describes an alpha factor that gets applied - to the result of the composition operation combining it with the destination. +static const CompositionFunctionSolid *functionForModeSolid = qt_functionForModeSolid_C; +static const CompositionFunctionSolid64 *functionForModeSolid64 = qt_functionForModeSolid64_C; - The intent is that if const_alpha == 0. we get back dest, and if const_alpha == 1. - we get the unmodified operation +extern CompositionFunction qt_functionForMode_C[]; +extern CompositionFunction64 qt_functionForMode64_C[]; - result = src op dest - dest = result * const_alpha + dest * (1. - const_alpha) - - This means that in the comments below, the first line is the const_alpha==255 case, the - second line the general one. - - In the lines below: - s == src, sa == alpha(src), sia = 1 - alpha(src) - d == dest, da == alpha(dest), dia = 1 - alpha(dest) - ca = const_alpha, cia = 1 - const_alpha - - The methods exist in two variants. One where we have a constant source, the other - where the source is an array of pixels. -*/ - -/* - result = 0 - d = d * cia -*/ -#define comp_func_Clear_impl(dest, length, const_alpha)\ -{\ - if (const_alpha == 255) {\ - QT_MEMFILL_UINT(dest, length, 0);\ - } else {\ - int ialpha = 255 - const_alpha;\ - PRELOAD_INIT(dest)\ - for (int i = 0; i < length; ++i) {\ - PRELOAD_COND(dest)\ - dest[i] = BYTE_MUL(dest[i], ialpha);\ - }\ - }\ -} - -void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint const_alpha) -{ - comp_func_Clear_impl(dest, length, const_alpha); -} - -void QT_FASTCALL comp_func_solid_Clear_rgb64(QRgba64 *dest, int length, QRgba64, uint const_alpha) -{ - if (const_alpha == 255) - qt_memfill64((quint64*)dest, 0, length); - else { - int ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha255(dest[i], ialpha); - } - } -} - -void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha) -{ - comp_func_Clear_impl(dest, length, const_alpha); -} - -void QT_FASTCALL comp_func_Clear_rgb64(QRgba64 *dest, const QRgba64 *, int length, uint const_alpha) -{ - if (const_alpha == 255) - qt_memfill64((quint64*)dest, 0, length); - else { - int ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha255(dest[i], ialpha); - } - } -} - -/* - result = s - dest = s * ca + d * cia -*/ -void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) { - QT_MEMFILL_UINT(dest, length, color); - } else { - int ialpha = 255 - const_alpha; - color = BYTE_MUL(color, const_alpha); - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = color + BYTE_MUL(dest[i], ialpha); - } - } -} - -void QT_FASTCALL comp_func_solid_Source_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - if (const_alpha == 255) - qt_memfill64((quint64*)dest, color, length); - else { - int ialpha = 255 - const_alpha; - color = multiplyAlpha255(color, const_alpha); - for (int i = 0; i < length; ++i) { - dest[i] = color + multiplyAlpha255(dest[i], ialpha); - } - } -} - -void QT_FASTCALL comp_func_Source(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - ::memcpy(dest, src, length * sizeof(uint)); - } else { - int ialpha = 255 - const_alpha; - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha); - } - } -} - -void QT_FASTCALL comp_func_Source_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - ::memcpy(dest, src, length * sizeof(quint64)); - else { - int ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - dest[i] = interpolate255(src[i], const_alpha, dest[i], ialpha); - } - } -} - -void QT_FASTCALL comp_func_solid_Destination(uint *, int, uint, uint) -{ -} - -void QT_FASTCALL comp_func_solid_Destination_rgb64(QRgba64 *, int, QRgba64, uint) -{ -} - -void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint) -{ -} - -void QT_FASTCALL comp_func_Destination_rgb64(QRgba64 *, const QRgba64 *, int, uint) -{ -} - -/* - result = s + d * sia - dest = (s + d * sia) * ca + d * cia - = s * ca + d * (sia * ca + cia) - = s * ca + d * (1 - sa*ca) -*/ -void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha) -{ - if ((const_alpha & qAlpha(color)) == 255) { - QT_MEMFILL_UINT(dest, length, color); - } else { - if (const_alpha != 255) - color = BYTE_MUL(color, const_alpha); - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color)); - } - } -} - -void QT_FASTCALL comp_func_solid_SourceOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - if (const_alpha == 255 && color.isOpaque()) { - qt_memfill64((quint64*)dest, color, length); - } else { - if (const_alpha != 255) - color = multiplyAlpha255(color, const_alpha); - for (int i = 0; i < length; ++i) { - dest[i] = color + multiplyAlpha65535(dest[i], 65535 - color.alpha()); - } - } -} - -void QT_FASTCALL comp_func_SourceOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = src[i]; - if (s >= 0xff000000) - dest[i] = s; - else if (s != 0) - dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); - } - } else { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); - } - } -} - -void QT_FASTCALL comp_func_SourceOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - QRgba64 s = src[i]; - if (s.isOpaque()) - dest[i] = s; - else if (!s.isTransparent()) - dest[i] = s + multiplyAlpha65535(dest[i], 65535 - s.alpha()); - } - } else { - for (int i = 0; i < length; ++i) { - QRgba64 s = multiplyAlpha255(src[i], const_alpha); - dest[i] = s + multiplyAlpha65535(dest[i], 65535 - s.alpha()); - } - } -} - -/* - result = d + s * dia - dest = (d + s * dia) * ca + d * cia - = d + s * dia * ca -*/ -void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha != 255) - color = BYTE_MUL(color, const_alpha); - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = d + BYTE_MUL(color, qAlpha(~d)); - } -} - -void QT_FASTCALL comp_func_solid_DestinationOver_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - if (const_alpha != 255) - color = multiplyAlpha255(color, const_alpha); - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - dest[i] = d + multiplyAlpha65535(color, 65535 - d.alpha()); - } -} - -void QT_FASTCALL comp_func_DestinationOver(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - dest[i] = d + BYTE_MUL(src[i], qAlpha(~d)); - } - } else { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = d + BYTE_MUL(s, qAlpha(~d)); - } - } -} - -void QT_FASTCALL comp_func_DestinationOver_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - dest[i] = d + multiplyAlpha65535(src[i], 65535 - d.alpha()); - } - } else { - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - QRgba64 s = multiplyAlpha255(src[i], const_alpha); - dest[i] = d + multiplyAlpha65535(s, 65535 - d.alpha()); - } - } -} - -/* - result = s * da - dest = s * da * ca + d * cia -*/ -void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha) -{ - PRELOAD_INIT(dest) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = BYTE_MUL(color, qAlpha(dest[i])); - } - } else { - color = BYTE_MUL(color, const_alpha); - uint cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia); - } - } -} - -void QT_FASTCALL comp_func_solid_SourceIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha65535(color, dest[i].alpha()); - } - } else { - uint ca = const_alpha * 257; - uint cia = 65535 - ca; - color = multiplyAlpha65535(color, ca); - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - dest[i] = interpolate65535(color, d.alpha(), d, cia); - } - } -} - -void QT_FASTCALL comp_func_SourceIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = BYTE_MUL(src[i], qAlpha(dest[i])); - } - } else { - uint cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia); - } - } -} - -void QT_FASTCALL comp_func_SourceIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha65535(src[i], dest[i].alpha()); - } - } else { - uint ca = const_alpha * 257; - uint cia = 65535 - ca; - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - QRgba64 s = multiplyAlpha65535(src[i], ca); - dest[i] = interpolate65535(s, d.alpha(), d, cia); - } - } -} - -/* - result = d * sa - dest = d * sa * ca + d * cia - = d * (sa * ca + cia) -*/ -void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha) -{ - uint a = qAlpha(color); - if (const_alpha != 255) { - a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - } - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = BYTE_MUL(dest[i], a); - } -} - -void QT_FASTCALL comp_func_solid_DestinationIn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - uint a = color.alpha(); - uint ca64k = const_alpha * 257; - if (const_alpha != 255) - a = qt_div_65535(a * ca64k) + 65535 - ca64k; - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha65535(dest[i], a); - } -} - -void QT_FASTCALL comp_func_DestinationIn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = BYTE_MUL(dest[i], qAlpha(src[i])); - } - } else { - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia; - dest[i] = BYTE_MUL(dest[i], a); - } - } -} - -void QT_FASTCALL comp_func_DestinationIn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha65535(dest[i], src[i].alpha()); - } - } else { - uint ca = const_alpha * 257; - uint cia = 65535 - ca; - for (int i = 0; i < length; ++i) { - uint a = qt_div_65535(src[i].alpha() * ca) + cia; - dest[i] = multiplyAlpha65535(dest[i], a); - } - } -} - -/* - result = s * dia - dest = s * dia * ca + d * cia -*/ - -void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha) -{ - PRELOAD_INIT(dest) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = BYTE_MUL(color, qAlpha(~dest[i])); - } - } else { - color = BYTE_MUL(color, const_alpha); - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia); - } - } -} - -void QT_FASTCALL comp_func_solid_SourceOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha65535(color, 65535 - dest[i].alpha()); - } - } else { - uint ca = const_alpha * 257; - uint cia = 65535 - ca; - color = multiplyAlpha65535(color, ca); - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - dest[i] = interpolate65535(color, 65535 - d.alpha(), d, cia); - } - } -} - -void QT_FASTCALL comp_func_SourceOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i])); - } - } else { - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = BYTE_MUL(src[i], const_alpha); - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia); - } - } -} - -void QT_FASTCALL comp_func_SourceOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha65535(src[i], 65535 - dest[i].alpha()); - } - } else { - uint ca = const_alpha * 257; - uint cia = 65535 - ca; - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - QRgba64 s = multiplyAlpha65535(src[i], ca); - dest[i] = interpolate65535(s, 65535 - d.alpha(), d, cia); - } - } -} - -/* - result = d * sia - dest = d * sia * ca + d * cia - = d * (sia * ca + cia) -*/ -void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha) -{ - uint a = qAlpha(~color); - if (const_alpha != 255) - a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = BYTE_MUL(dest[i], a); - } -} - -void QT_FASTCALL comp_func_solid_DestinationOut_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - uint a = 65535 - color.alpha(); - uint ca64k = const_alpha * 257; - if (const_alpha != 255) - a = qt_div_65535(a * ca64k) + 65535 - ca64k; - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha65535(dest[i], a); - } -} - -void QT_FASTCALL comp_func_DestinationOut(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i])); - } - } else { - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia; - dest[i] = BYTE_MUL(dest[i], sia); - } - } -} - -void QT_FASTCALL comp_func_DestinationOut_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = multiplyAlpha65535(dest[i], 65535 - src[i].alpha()); - } - } else { - uint ca = const_alpha * 257; - uint cia = 65535 - ca; - for (int i = 0; i < length; ++i) { - uint a = qt_div_65535((65535 - src[i].alpha()) * ca) + cia; - dest[i] = multiplyAlpha65535(dest[i], a); - } - } -} - -/* - result = s*da + d*sia - dest = s*da*ca + d*sia*ca + d *cia - = s*ca * da + d * (sia*ca + cia) - = s*ca * da + d * (1 - sa*ca) -*/ -void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha != 255) { - color = BYTE_MUL(color, const_alpha); - } - uint sia = qAlpha(~color); - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia); - } -} - -void QT_FASTCALL comp_func_solid_SourceAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - if (const_alpha != 255) - color = multiplyAlpha255(color, const_alpha); - uint sia = 65535 - color.alpha(); - for (int i = 0; i < length; ++i) { - dest[i] = interpolate65535(color, dest[i].alpha(), dest[i], sia); - } -} - -void QT_FASTCALL comp_func_SourceAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = src[i]; - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); - } - } else { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = BYTE_MUL(src[i], const_alpha); - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); - } - } -} - -void QT_FASTCALL comp_func_SourceAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - QRgba64 s = src[i]; - QRgba64 d = dest[i]; - dest[i] = interpolate65535(s, d.alpha(), d, 65535 - s.alpha()); - } - } else { - for (int i = 0; i < length; ++i) { - QRgba64 s = multiplyAlpha255(src[i], const_alpha); - QRgba64 d = dest[i]; - dest[i] = interpolate65535(s, d.alpha(), d, 65535 - s.alpha()); - } - } -} - -/* - result = d*sa + s*dia - dest = d*sa*ca + s*dia*ca + d *cia - = s*ca * dia + d * (sa*ca + cia) -*/ -void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha) -{ - uint a = qAlpha(color); - if (const_alpha != 255) { - color = BYTE_MUL(color, const_alpha); - a = qAlpha(color) + 255 - const_alpha; - } - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d)); - } -} - -void QT_FASTCALL comp_func_solid_DestinationAtop_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - uint a = color.alpha(); - if (const_alpha != 255) { - color = multiplyAlpha255(color, const_alpha); - a = color.alpha() + 65535 - (const_alpha * 257); - } - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - dest[i] = interpolate65535(d, a, color, 65535 - d.alpha()); - } -} - -void QT_FASTCALL comp_func_DestinationAtop(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = src[i]; - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d)); - } - } else { - int cia = 255 - const_alpha; - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint s = BYTE_MUL(src[i], const_alpha); - uint d = dest[i]; - uint a = qAlpha(s) + cia; - dest[i] = INTERPOLATE_PIXEL_255(d, a, s, qAlpha(~d)); - } - } -} - -void QT_FASTCALL comp_func_DestinationAtop_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - QRgba64 s = src[i]; - QRgba64 d = dest[i]; - dest[i] = interpolate65535(d, s.alpha(), s, 65535 - d.alpha()); - } - } else { - int ca = const_alpha * 257; - int cia = 65535 - ca; - for (int i = 0; i < length; ++i) { - QRgba64 s = multiplyAlpha65535(src[i], ca); - QRgba64 d = dest[i]; - uint a = s.alpha() + cia; - dest[i] = interpolate65535(d, a, s, 65535 - d.alpha()); - } - } -} - -/* - result = d*sia + s*dia - dest = d*sia*ca + s*dia*ca + d *cia - = s*ca * dia + d * (sia*ca + cia) - = s*ca * dia + d * (1 - sa*ca) -*/ -void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha != 255) - color = BYTE_MUL(color, const_alpha); - uint sia = qAlpha(~color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia); - } -} - -void QT_FASTCALL comp_func_solid_XOR_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - if (const_alpha != 255) - color = multiplyAlpha255(color, const_alpha); - uint sia = 65535 - color.alpha(); - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - dest[i] = interpolate65535(color, 65535 - d.alpha(), d, sia); - } -} - -void QT_FASTCALL comp_func_XOR(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - PRELOAD_INIT2(dest, src) - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); - } - } else { - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = BYTE_MUL(src[i], const_alpha); - dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); - } - } -} - -void QT_FASTCALL comp_func_XOR_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - QRgba64 s = src[i]; - dest[i] = interpolate65535(s, 65535 - d.alpha(), d, 65535 - s.alpha()); - } - } else { - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - QRgba64 s = multiplyAlpha255(src[i], const_alpha); - dest[i] = interpolate65535(s, 65535 - d.alpha(), d, 65535 - s.alpha()); - } - } -} - -struct QFullCoverage { - inline void store(uint *dest, const uint src) const - { - *dest = src; - } -}; - -struct QPartialCoverage { - inline QPartialCoverage(uint const_alpha) - : ca(const_alpha) - , ica(255 - const_alpha) - { - } - - inline void store(uint *dest, const uint src) const - { - *dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica); - } - -private: - const uint ca; - const uint ica; -}; - -static inline int mix_alpha(int da, int sa) -{ - return 255 - ((255 - sa) * (255 - da) >> 8); -} - -/* - Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa) - = Sca + Dca -*/ -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int length, uint color, const T &coverage) -{ - uint s = color; - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - d = comp_func_Plus_one_pixel(d, s); - coverage.store(&dest[i], d); - } -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl_rgb64(QRgba64 *dest, int length, QRgba64 color, const T &coverage) -{ - QRgba64 s = color; - for (int i = 0; i < length; ++i) { - QRgba64 d = dest[i]; - d = comp_func_Plus_one_pixel(d, s); - coverage.store(&dest[i], d); - } -} - -void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Plus_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Plus_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -void QT_FASTCALL comp_func_solid_Plus_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = addWithSaturation(dest[i], color); - } - } else { - for (int i = 0; i < length; ++i) { - QRgba64 d = addWithSaturation(dest[i], color); - dest[i] = interpolate255(d, const_alpha, dest[i], 255 - const_alpha); - } - } -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - d = comp_func_Plus_one_pixel(d, s); - - coverage.store(&dest[i], d); - } -} - -void QT_FASTCALL comp_func_Plus(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Plus_impl(dest, src, length, QFullCoverage()); - else - comp_func_Plus_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -void QT_FASTCALL comp_func_Plus_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) { - for (int i = 0; i < length; ++i) { - dest[i] = addWithSaturation(dest[i], src[i]); - } - } else { - for (int i = 0; i < length; ++i) { - QRgba64 d = addWithSaturation(dest[i], src[i]); - dest[i] = interpolate255(d, const_alpha, dest[i], 255 - const_alpha); - } - } -} - -/* - Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int multiply_op(int dst, int src, int da, int sa) -{ - return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) multiply_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) multiply_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Multiply(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Multiply_impl(dest, src, length, QFullCoverage()); - else - comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) - = Sca + Dca - Sca.Dca -*/ -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) 255 - qt_div_255((255-a) * (255-b)) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Screen_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) 255 - (((255-a) * (255-b)) >> 8) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Screen_impl(dest, src, length, QFullCoverage()); - else - comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if 2.Dca < Da - Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int overlay_op(int dst, int src, int da, int sa) -{ - const int temp = src * (255 - da) + dst * (255 - sa); - if (2 * dst < da) - return qt_div_255(2 * src * dst + temp); - else - return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) overlay_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) overlay_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Overlay(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Overlay_impl(dest, src, length, QFullCoverage()); - else - comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) - Da' = Sa + Da - Sa.Da -*/ -static inline int darken_op(int dst, int src, int da, int sa) -{ - return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) darken_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Darken_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) darken_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Darken(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Darken_impl(dest, src, length, QFullCoverage()); - else - comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) - Da' = Sa + Da - Sa.Da -*/ -static inline int lighten_op(int dst, int src, int da, int sa) -{ - return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) lighten_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) lighten_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Lighten(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Lighten_impl(dest, src, length, QFullCoverage()); - else - comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if Sca.Da + Dca.Sa >= Sa.Da - Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int color_dodge_op(int dst, int src, int da, int sa) -{ - const int sa_da = sa * da; - const int dst_sa = dst * sa; - const int src_da = src * da; - - const int temp = src * (255 - da) + dst * (255 - sa); - if (src_da + dst_sa >= sa_da) - return qt_div_255(sa_da + temp); - else - return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a,b) color_dodge_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) color_dodge_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_ColorDodge(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_ColorDodge_impl(dest, src, length, QFullCoverage()); - else - comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if Sca.Da + Dca.Sa <= Sa.Da - Dca' = Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int color_burn_op(int dst, int src, int da, int sa) -{ - const int src_da = src * da; - const int dst_sa = dst * sa; - const int sa_da = sa * da; - - const int temp = src * (255 - da) + dst * (255 - sa); - - if (src == 0 || src_da + dst_sa <= sa_da) - return qt_div_255(temp); - return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) color_burn_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) color_burn_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_ColorBurn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_ColorBurn_impl(dest, src, length, QFullCoverage()); - else - comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if 2.Sca < Sa - Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise - Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline uint hardlight_op(int dst, int src, int da, int sa) -{ - const uint temp = src * (255 - da) + dst * (255 - sa); - - if (2 * src < sa) - return qt_div_255(2 * src * dst + temp); - else - return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) hardlight_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) hardlight_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_HardLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_HardLight_impl(dest, src, length, QFullCoverage()); - else - comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - if 2.Sca <= Sa - Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise if 2.Sca > Sa and 4.Dca <= Da - Dca' = Dca.Sa + Da.(2.Sca - Sa).(4.Dca/Da.(4.Dca/Da + 1).(Dca/Da - 1) + 7.Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) - otherwise if 2.Sca > Sa and 4.Dca > Da - Dca' = Dca.Sa + Da.(2.Sca - Sa).((Dca/Da)^0.5 - Dca/Da) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -static inline int soft_light_op(int dst, int src, int da, int sa) -{ - const int src2 = src << 1; - const int dst_np = da != 0 ? (255 * dst) / da : 0; - const int temp = (src * (255 - da) + dst * (255 - sa)) * 255; - - if (src2 < sa) - return (dst * (sa * 255 + (src2 - sa) * (255 - dst_np)) + temp) / 65025; - else if (4 * dst <= da) - return (dst * sa * 255 + da * (src2 - sa) * ((((16 * dst_np - 12 * 255) * dst_np + 3 * 65025) * dst_np) / 65025) + temp) / 65025; - else { - return (dst * sa * 255 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 255))) - dst_np) + temp) / 65025; - } -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) soft_light_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) soft_light_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_SoftLight_impl(dest, src, length, QFullCoverage()); - else - comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa) - = Sca + Dca - 2.min(Sca.Da, Dca.Sa) -*/ -static inline int difference_op(int dst, int src, int da, int sa) -{ - return src + dst - qt_div_255(2 * qMin(src * da, dst * sa)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) difference_op(a, b, da, sa) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Difference_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) difference_op(a, b, da, sa) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Difference(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Difference_impl(dest, src, length, QFullCoverage()); - else - comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -/* - Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) -*/ -template -Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(uint *dest, int length, uint color, const T &coverage) -{ - int sa = qAlpha(color); - int sr = qRed(color); - int sg = qGreen(color); - int sb = qBlue(color); - - PRELOAD_INIT(dest) - for (int i = 0; i < length; ++i) { - PRELOAD_COND(dest) - uint d = dest[i]; - int da = qAlpha(d); - -#define OP(a, b) (a + b - qt_div_255(2*(a*b))) - int r = OP( qRed(d), sr); - int b = OP( qBlue(d), sb); - int g = OP(qGreen(d), sg); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage()); - else - comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha)); -} - -template -Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage) -{ - PRELOAD_INIT2(dest, src) - for (int i = 0; i < length; ++i) { - PRELOAD_COND2(dest, src) - uint d = dest[i]; - uint s = src[i]; - - int da = qAlpha(d); - int sa = qAlpha(s); - -#define OP(a, b) (a + b - ((a*b) >> 7)) - int r = OP( qRed(d), qRed(s)); - int b = OP( qBlue(d), qBlue(s)); - int g = OP(qGreen(d), qGreen(s)); - int a = mix_alpha(da, sa); -#undef OP - - coverage.store(&dest[i], qRgba(r, g, b, a)); - } -} - -void QT_FASTCALL comp_func_Exclusion(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha) -{ - if (const_alpha == 255) - comp_func_Exclusion_impl(dest, src, length, QFullCoverage()); - else - comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha)); -} - -void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) - *dest++ |= color; -} - -void QT_FASTCALL rasterop_SourceOrDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) - *dest++ |= *src++; -} - -void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color |= 0xff000000; - while (length--) - *dest++ &= color; -} - -void QT_FASTCALL rasterop_SourceAndDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (*src & *dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color &= 0x00ffffff; - while (length--) - *dest++ ^= color; -} - -void QT_FASTCALL rasterop_SourceXorDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (*src ^ *dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color; - while (length--) { - *dest = (color & ~(*dest)) | 0xff000000; - ++dest; - } -} - -void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (~(*src) & ~(*dest)) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color | 0xff000000; - while (length--) { - *dest = color | ~(*dest); - ++dest; - } -} - -void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = ~(*src) | ~(*dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color & 0x00ffffff; - while (length--) { - *dest = color ^ (*dest); - ++dest; - } -} - -void QT_FASTCALL rasterop_NotSourceXorDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = ((~(*src)) ^ (*dest)) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length, - uint color, uint const_alpha) -{ - Q_UNUSED(const_alpha); - qt_memfill(dest, ~color | 0xff000000, length); -} - -void QT_FASTCALL rasterop_NotSource(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, - int length, uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) - *dest++ = ~(*src++) | 0xff000000; -} - -void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color | 0xff000000; - while (length--) { - *dest = color & *dest; - ++dest; - } -} - -void QT_FASTCALL rasterop_NotSourceAndDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (~(*src) & *dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (color & ~(*dest)) | 0xff000000; - ++dest; - } -} - -void QT_FASTCALL rasterop_SourceAndNotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (*src & ~(*dest)) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_NotSourceOrDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (~(*src) | *dest) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_NotSourceOrDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - color = ~color | 0xff000000; - while (length--) - *dest++ |= color; -} - -void QT_FASTCALL rasterop_SourceOrNotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (*src | ~(*dest)) | 0xff000000; - ++dest; ++src; - } -} - -void QT_FASTCALL rasterop_solid_SourceOrNotDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(const_alpha); - while (length--) { - *dest = (color | ~(*dest)) | 0xff000000; - ++dest; - } -} - -void QT_FASTCALL rasterop_ClearDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(src); - comp_func_solid_SourceOver (dest, length, 0xff000000, const_alpha); -} - -void QT_FASTCALL rasterop_solid_ClearDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(color); - comp_func_solid_SourceOver (dest, length, 0xff000000, const_alpha); -} - -void QT_FASTCALL rasterop_SetDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(src); - comp_func_solid_SourceOver (dest, length, 0xffffffff, const_alpha); -} - -void QT_FASTCALL rasterop_solid_SetDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(color); - comp_func_solid_SourceOver (dest, length, 0xffffffff, const_alpha); -} - -void QT_FASTCALL rasterop_NotDestination(uint *Q_DECL_RESTRICT dest, - const uint *Q_DECL_RESTRICT src, - int length, - uint const_alpha) -{ - Q_UNUSED(src); - rasterop_solid_SourceXorDestination (dest, length, 0x00ffffff, const_alpha); -} - -void QT_FASTCALL rasterop_solid_NotDestination(uint *Q_DECL_RESTRICT dest, - int length, - uint color, - uint const_alpha) -{ - Q_UNUSED(color); - rasterop_solid_SourceXorDestination (dest, length, 0x00ffffff, const_alpha); -} - -static CompositionFunctionSolid functionForModeSolid_C[] = { - comp_func_solid_SourceOver, - comp_func_solid_DestinationOver, - comp_func_solid_Clear, - comp_func_solid_Source, - comp_func_solid_Destination, - comp_func_solid_SourceIn, - comp_func_solid_DestinationIn, - comp_func_solid_SourceOut, - comp_func_solid_DestinationOut, - comp_func_solid_SourceAtop, - comp_func_solid_DestinationAtop, - comp_func_solid_XOR, - comp_func_solid_Plus, - comp_func_solid_Multiply, - comp_func_solid_Screen, - comp_func_solid_Overlay, - comp_func_solid_Darken, - comp_func_solid_Lighten, - comp_func_solid_ColorDodge, - comp_func_solid_ColorBurn, - comp_func_solid_HardLight, - comp_func_solid_SoftLight, - comp_func_solid_Difference, - comp_func_solid_Exclusion, - rasterop_solid_SourceOrDestination, - rasterop_solid_SourceAndDestination, - rasterop_solid_SourceXorDestination, - rasterop_solid_NotSourceAndNotDestination, - rasterop_solid_NotSourceOrNotDestination, - rasterop_solid_NotSourceXorDestination, - rasterop_solid_NotSource, - rasterop_solid_NotSourceAndDestination, - rasterop_solid_SourceAndNotDestination, - rasterop_solid_NotSourceOrDestination, - rasterop_solid_SourceOrNotDestination, - rasterop_solid_ClearDestination, - rasterop_solid_SetDestination, - rasterop_solid_NotDestination -}; - -static CompositionFunctionSolid64 functionForModeSolid64_C[] = { - comp_func_solid_SourceOver_rgb64, - comp_func_solid_DestinationOver_rgb64, - comp_func_solid_Clear_rgb64, - comp_func_solid_Source_rgb64, - comp_func_solid_Destination_rgb64, - comp_func_solid_SourceIn_rgb64, - comp_func_solid_DestinationIn_rgb64, - comp_func_solid_SourceOut_rgb64, - comp_func_solid_DestinationOut_rgb64, - comp_func_solid_SourceAtop_rgb64, - comp_func_solid_DestinationAtop_rgb64, - comp_func_solid_XOR_rgb64, - comp_func_solid_Plus_rgb64, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const CompositionFunctionSolid *functionForModeSolid = functionForModeSolid_C; -static const CompositionFunctionSolid64 *functionForModeSolid64 = functionForModeSolid64_C; - -static CompositionFunction functionForMode_C[] = { - comp_func_SourceOver, - comp_func_DestinationOver, - comp_func_Clear, - comp_func_Source, - comp_func_Destination, - comp_func_SourceIn, - comp_func_DestinationIn, - comp_func_SourceOut, - comp_func_DestinationOut, - comp_func_SourceAtop, - comp_func_DestinationAtop, - comp_func_XOR, - comp_func_Plus, - comp_func_Multiply, - comp_func_Screen, - comp_func_Overlay, - comp_func_Darken, - comp_func_Lighten, - comp_func_ColorDodge, - comp_func_ColorBurn, - comp_func_HardLight, - comp_func_SoftLight, - comp_func_Difference, - comp_func_Exclusion, - rasterop_SourceOrDestination, - rasterop_SourceAndDestination, - rasterop_SourceXorDestination, - rasterop_NotSourceAndNotDestination, - rasterop_NotSourceOrNotDestination, - rasterop_NotSourceXorDestination, - rasterop_NotSource, - rasterop_NotSourceAndDestination, - rasterop_SourceAndNotDestination, - rasterop_NotSourceOrDestination, - rasterop_SourceOrNotDestination, - rasterop_ClearDestination, - rasterop_SetDestination, - rasterop_NotDestination -}; - -static CompositionFunction64 functionForMode64_C[] = { - comp_func_SourceOver_rgb64, - comp_func_DestinationOver_rgb64, - comp_func_Clear_rgb64, - comp_func_Source_rgb64, - comp_func_Destination_rgb64, - comp_func_SourceIn_rgb64, - comp_func_DestinationIn_rgb64, - comp_func_SourceOut_rgb64, - comp_func_DestinationOut_rgb64, - comp_func_SourceAtop_rgb64, - comp_func_DestinationAtop_rgb64, - comp_func_XOR_rgb64, - comp_func_Plus_rgb64, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const CompositionFunction *functionForMode = functionForMode_C; -static const CompositionFunction64 *functionForMode64 = functionForMode64_C; +static const CompositionFunction *functionForMode = qt_functionForMode_C; +static const CompositionFunction64 *functionForMode64 = qt_functionForMode64_C; static TextureBlendType getBlendType(const QSpanData *data) { @@ -8460,9 +6309,6 @@ void qt_memfill32(quint32 *dest, quint32 color, int count) void qInitDrawhelperAsm() { - CompositionFunction *functionForModeAsm = 0; - CompositionFunctionSolid *functionForModeSolidAsm = 0; - const uint features = qCpuFeatures(); Q_UNUSED(features); #ifdef __SSE2__ @@ -8547,9 +6393,15 @@ void qInitDrawhelperAsm() qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_avx2; } #endif + extern void QT_FASTCALL comp_func_SourceOver_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, uint color, uint const_alpha); + extern void QT_FASTCALL comp_func_Source_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + extern void QT_FASTCALL comp_func_Plus_sse2(uint *destPixels, const uint *srcPixels, int length, uint const_alpha); + qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_sse2; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_sse2; + qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_sse2; + qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_sse2; - functionForModeAsm = qt_functionForMode_SSE2; - functionForModeSolidAsm = qt_functionForModeSolid_SSE2; #endif // SSE2 #if defined(__ARM_NEON__) && !defined(Q_OS_IOS) @@ -8575,9 +6427,9 @@ void qInitDrawhelperAsm() qDrawHelper[QImage::Format_RGB16].alphamapBlit = qt_alphamapblit_quint16_neon; - functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon; - functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon; - functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon; + qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = qt_blend_argb32_on_argb32_scanline_neon; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_neon; + qt_functionForMode_C[QPainter::CompositionMode_Plus] = comp_func_Plus_neon; destFetchProc[QImage::Format_RGB16] = qt_destFetchRGB16_neon; destStoreProc[QImage::Format_RGB16] = qt_destStoreRGB16_neon; @@ -8597,25 +6449,25 @@ void qInitDrawhelperAsm() #if defined(QT_COMPILER_SUPPORTS_MIPS_DSP) || defined(QT_COMPILER_SUPPORTS_MIPS_DSPR2) if (features & (DSP | DSPR2)) { // Composition functions are all DSP r1 - functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_asm_mips_dsp; - functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_mips_dsp; - functionForMode_C[QPainter::CompositionMode_DestinationOver] = comp_func_DestinationOver_mips_dsp; - functionForMode_C[QPainter::CompositionMode_SourceIn] = comp_func_SourceIn_mips_dsp; - functionForMode_C[QPainter::CompositionMode_DestinationIn] = comp_func_DestinationIn_mips_dsp; - functionForMode_C[QPainter::CompositionMode_DestinationOut] = comp_func_DestinationOut_mips_dsp; - functionForMode_C[QPainter::CompositionMode_SourceAtop] = comp_func_SourceAtop_mips_dsp; - functionForMode_C[QPainter::CompositionMode_DestinationAtop] = comp_func_DestinationAtop_mips_dsp; - functionForMode_C[QPainter::CompositionMode_Xor] = comp_func_XOR_mips_dsp; - functionForMode_C[QPainter::CompositionMode_SourceOut] = comp_func_SourceOut_mips_dsp; - - functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_DestinationOver] = comp_func_solid_DestinationOver_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_SourceIn] = comp_func_solid_SourceIn_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_DestinationIn] = comp_func_solid_DestinationIn_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_SourceAtop] = comp_func_solid_SourceAtop_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_DestinationAtop] = comp_func_solid_DestinationAtop_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_Xor] = comp_func_solid_XOR_mips_dsp; - functionForModeSolid_C[QPainter::CompositionMode_SourceOut] = comp_func_solid_SourceOut_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_SourceOver] = comp_func_SourceOver_asm_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_Source] = comp_func_Source_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_DestinationOver] = comp_func_DestinationOver_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_SourceIn] = comp_func_SourceIn_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_DestinationIn] = comp_func_DestinationIn_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_DestinationOut] = comp_func_DestinationOut_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_SourceAtop] = comp_func_SourceAtop_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_DestinationAtop] = comp_func_DestinationAtop_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_Xor] = comp_func_XOR_mips_dsp; + qt_functionForMode_C[QPainter::CompositionMode_SourceOut] = comp_func_SourceOut_mips_dsp; + + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOver] = comp_func_solid_SourceOver_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationOver] = comp_func_solid_DestinationOver_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceIn] = comp_func_solid_SourceIn_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationIn] = comp_func_solid_DestinationIn_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceAtop] = comp_func_solid_SourceAtop_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_DestinationAtop] = comp_func_solid_DestinationAtop_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_Xor] = comp_func_solid_XOR_mips_dsp; + qt_functionForModeSolid_C[QPainter::CompositionMode_SourceOut] = comp_func_solid_SourceOut_mips_dsp; qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp; qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_mips_dsp; @@ -8642,20 +6494,6 @@ void qInitDrawhelperAsm() #endif // QT_COMPILER_SUPPORTS_MIPS_DSPR2 } #endif // QT_COMPILER_SUPPORTS_MIPS_DSP || QT_COMPILER_SUPPORTS_MIPS_DSPR2 - - if (functionForModeSolidAsm) { - const int destinationMode = QPainter::CompositionMode_Destination; - functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode]; - - // use the default qdrawhelper implementation for the - // extended composition modes - for (int mode = 12; mode < 24; ++mode) - functionForModeSolidAsm[mode] = functionForModeSolid_C[mode]; - - functionForModeSolid = functionForModeSolidAsm; - } - if (functionForModeAsm) - functionForMode = functionForModeAsm; } QT_END_NAMESPACE diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index d584e392e9..019e1864f9 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -1065,86 +1065,6 @@ inline int comp_func_Plus_one_pixel(uint d, const uint s) #undef MIX #undef AMIX -// prototypes of all the composition functions -void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, uint const_alpha); -void QT_FASTCALL comp_func_Source(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Destination(uint *, const uint *, int, uint); -void QT_FASTCALL comp_func_SourceIn(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_SourceOut(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_DestinationOut(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_SourceAtop(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_XOR(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Plus(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Multiply(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Overlay(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Darken(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Lighten(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_ColorDodge(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_ColorBurn(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_HardLight(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_SoftLight(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Difference(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL comp_func_Exclusion(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceOrDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceAndDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceXorDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceAndNotDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceOrNotDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceXorDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSource(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceAndDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceAndNotDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotSourceOrDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SourceOrNotDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_ClearDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_SetDestination(uint *dest, const uint *src, int length, uint const_alpha); -void QT_FASTCALL rasterop_NotDestination(uint *dest, const uint *src, int length, uint const_alpha); -// prototypes of all the solid composition functions -void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Destination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceAndDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceXorDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceAndNotDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceOrNotDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceXorDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotSourceOrDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SourceOrNotDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_ClearDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_SetDestination(uint *dest, int length, uint color, uint const_alpha); -void QT_FASTCALL rasterop_solid_NotDestination(uint *dest, int length, uint color, uint const_alpha); - - struct QPixelLayout; typedef const uint *(QT_FASTCALL *ConvertFunc)(uint *buffer, const uint *src, int count, const QPixelLayout *layout, const QRgb *clut); diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp index 17e9d462fd..d7f3686e54 100644 --- a/src/gui/painting/qdrawhelper_sse2.cpp +++ b/src/gui/painting/qdrawhelper_sse2.cpp @@ -311,90 +311,6 @@ void QT_FASTCALL comp_func_solid_SourceOver_sse2(uint *destPixels, int length, u } } -#ifndef QDRAWHELPER_AVX -CompositionFunctionSolid qt_functionForModeSolid_SSE2[numCompositionFunctions] = { - comp_func_solid_SourceOver_sse2, - comp_func_solid_DestinationOver, - comp_func_solid_Clear, - comp_func_solid_Source, - comp_func_solid_Destination, - comp_func_solid_SourceIn, - comp_func_solid_DestinationIn, - comp_func_solid_SourceOut, - comp_func_solid_DestinationOut, - comp_func_solid_SourceAtop, - comp_func_solid_DestinationAtop, - comp_func_solid_XOR, - comp_func_solid_Plus, - comp_func_solid_Multiply, - comp_func_solid_Screen, - comp_func_solid_Overlay, - comp_func_solid_Darken, - comp_func_solid_Lighten, - comp_func_solid_ColorDodge, - comp_func_solid_ColorBurn, - comp_func_solid_HardLight, - comp_func_solid_SoftLight, - comp_func_solid_Difference, - comp_func_solid_Exclusion, - rasterop_solid_SourceOrDestination, - rasterop_solid_SourceAndDestination, - rasterop_solid_SourceXorDestination, - rasterop_solid_NotSourceAndNotDestination, - rasterop_solid_NotSourceOrNotDestination, - rasterop_solid_NotSourceXorDestination, - rasterop_solid_NotSource, - rasterop_solid_NotSourceAndDestination, - rasterop_solid_SourceAndNotDestination, - rasterop_solid_NotSourceOrDestination, - rasterop_solid_SourceOrNotDestination, - rasterop_solid_ClearDestination, - rasterop_solid_SetDestination, - rasterop_solid_NotDestination -}; - -CompositionFunction qt_functionForMode_SSE2[numCompositionFunctions] = { - comp_func_SourceOver_sse2, - comp_func_DestinationOver, - comp_func_Clear, - comp_func_Source_sse2, - comp_func_Destination, - comp_func_SourceIn, - comp_func_DestinationIn, - comp_func_SourceOut, - comp_func_DestinationOut, - comp_func_SourceAtop, - comp_func_DestinationAtop, - comp_func_XOR, - comp_func_Plus_sse2, - comp_func_Multiply, - comp_func_Screen, - comp_func_Overlay, - comp_func_Darken, - comp_func_Lighten, - comp_func_ColorDodge, - comp_func_ColorBurn, - comp_func_HardLight, - comp_func_SoftLight, - comp_func_Difference, - comp_func_Exclusion, - rasterop_SourceOrDestination, - rasterop_SourceAndDestination, - rasterop_SourceXorDestination, - rasterop_NotSourceAndNotDestination, - rasterop_NotSourceOrNotDestination, - rasterop_NotSourceXorDestination, - rasterop_NotSource, - rasterop_NotSourceAndDestination, - rasterop_SourceAndNotDestination, - rasterop_NotSourceOrDestination, - rasterop_SourceOrNotDestination, - rasterop_ClearDestination, - rasterop_SetDestination, - rasterop_NotDestination -}; -#endif - void qt_memfill16(quint16 *dest, quint16 value, int count) { if (count < 3) { -- cgit v1.2.3 From 964ccc58534aac436529007000d1c38d76c88834 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 13 Apr 2015 16:06:57 +0200 Subject: Remove separate SSE4 unpremultiply function Merges the SSE4 specific unpremultiply with the normal version, and adds a SSE2 fallback. There was no reason to split the two since compile time options will ensure the right version is inlined. Also adds short-cut for 0 and 255 values. Change-Id: Ie5aa262f6964219fd3062d4a498f697cf79a4595 Reviewed-by: Thiago Macieira --- src/gui/painting/qdrawhelper.cpp | 10 ++++---- src/gui/painting/qdrawhelper_sse4.cpp | 7 +++--- src/gui/painting/qdrawingprimitive_sse2_p.h | 21 ---------------- src/gui/painting/qrgb.h | 37 ++++++++++++++++++++++++++--- 4 files changed, 41 insertions(+), 34 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 37f2de98b6..2817a4a145 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -6704,24 +6704,22 @@ void qInitDrawhelperAsm() } #endif // SSSE3 -#if QT_COMPILER_SUPPORTS_SSE4_1 +#if defined(QT_COMPILER_SUPPORTS_SSE4_1) && !defined(__SSE4_1__) if (qCpuHasFeature(SSE4_1)) { -#if !defined(__SSE4_1__) extern const uint *QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); extern const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); - qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4; - qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_sse4; -#endif extern const uint *QT_FASTCALL convertARGB32FromARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); extern const uint *QT_FASTCALL convertRGBA8888FromARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); extern const uint *QT_FASTCALL convertRGBXFromARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); + qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4; + qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_sse4; qPixelLayouts[QImage::Format_ARGB32].convertFromARGB32PM = convertARGB32FromARGB32PM_sse4; qPixelLayouts[QImage::Format_RGBA8888].convertFromARGB32PM = convertRGBA8888FromARGB32PM_sse4; qPixelLayouts[QImage::Format_RGBX8888].convertFromARGB32PM = convertRGBXFromARGB32PM_sse4; } #endif -#if QT_COMPILER_SUPPORTS_AVX2 && !defined(__AVX2__) +#if defined(QT_COMPILER_SUPPORTS_AVX2) && !defined(__AVX2__) if (qCpuHasFeature(AVX2)) { extern const uint *QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); extern const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); diff --git a/src/gui/painting/qdrawhelper_sse4.cpp b/src/gui/painting/qdrawhelper_sse4.cpp index 43a3958997..8e0b2cbb18 100644 --- a/src/gui/painting/qdrawhelper_sse4.cpp +++ b/src/gui/painting/qdrawhelper_sse4.cpp @@ -32,7 +32,6 @@ ****************************************************************************/ #include -#include #if defined(QT_COMPILER_SUPPORTS_SSE4_1) @@ -54,7 +53,7 @@ const uint *QT_FASTCALL convertARGB32FromARGB32PM_sse4(uint *buffer, const uint const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = qUnpremultiply_sse4(src[i]); + buffer[i] = qUnpremultiply(src[i]); return buffer; } @@ -62,7 +61,7 @@ const uint *QT_FASTCALL convertRGBA8888FromARGB32PM_sse4(uint *buffer, const uin const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(qUnpremultiply_sse4(src[i])); + buffer[i] = ARGB2RGBA(qUnpremultiply(src[i])); return buffer; } @@ -70,7 +69,7 @@ const uint *QT_FASTCALL convertRGBXFromARGB32PM_sse4(uint *buffer, const uint *s const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(0xff000000 | qUnpremultiply_sse4(src[i])); + buffer[i] = ARGB2RGBA(0xff000000 | qUnpremultiply(src[i])); return buffer; } diff --git a/src/gui/painting/qdrawingprimitive_sse2_p.h b/src/gui/painting/qdrawingprimitive_sse2_p.h index 4d0790a502..fbee06e157 100644 --- a/src/gui/painting/qdrawingprimitive_sse2_p.h +++ b/src/gui/painting/qdrawingprimitive_sse2_p.h @@ -236,25 +236,4 @@ QT_END_NAMESPACE #endif // __SSE2__ -QT_BEGIN_NAMESPACE -#if QT_COMPILER_SUPPORTS_HERE(SSE4_1) -QT_FUNCTION_TARGET(SSE4_1) -inline QRgb qUnpremultiply_sse4(QRgb p) -{ - const uint alpha = qAlpha(p); - const uint invAlpha = qt_inv_premul_factor[alpha]; - const __m128i via = _mm_set1_epi32(invAlpha); - const __m128i vr = _mm_set1_epi32(0x8000); - __m128i vl = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(p)); - vl = _mm_mullo_epi32(vl, via); - vl = _mm_add_epi32(vl, vr); - vl = _mm_srai_epi32(vl, 16); - vl = _mm_insert_epi32(vl, alpha, 3); - vl = _mm_packus_epi32(vl, _mm_setzero_si128()); - vl = _mm_packus_epi16(vl, _mm_setzero_si128()); - return _mm_cvtsi128_si32(vl); -} -#endif -QT_END_NAMESPACE - #endif // QDRAWINGPRIMITIVE_SSE2_P_H diff --git a/src/gui/painting/qrgb.h b/src/gui/painting/qrgb.h index f7f2185bef..05b3a76bce 100644 --- a/src/gui/painting/qrgb.h +++ b/src/gui/painting/qrgb.h @@ -36,6 +36,11 @@ #include #include +#if defined(__SSE4_1__) +#include +#elif defined(__SSE2__) +#include +#endif QT_BEGIN_NAMESPACE @@ -87,19 +92,45 @@ inline Q_DECL_RELAXED_CONSTEXPR QRgb qPremultiply(QRgb x) Q_GUI_EXPORT extern const uint qt_inv_premul_factor[]; +#if defined(__SSE2__) +inline QRgb qUnpremultiply(QRgb p) +{ + const uint alpha = qAlpha(p); + if (alpha == 255 || alpha == 0) + return p; + const uint invAlpha = qt_inv_premul_factor[alpha]; + const __m128i via = _mm_set1_epi32(invAlpha); + const __m128i vr = _mm_set1_epi32(0x8000); +#ifdef __SSE4_1__ + __m128i vl = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(p)); + vl = _mm_mullo_epi32(vl, via); +#else + __m128i vl = _mm_unpacklo_epi8(_mm_cvtsi32_si128(p), _mm_setzero_si128()); + vl = _mm_unpacklo_epi16(vl, vl); + __m128i vll = _mm_mullo_epi16(vl, via); + __m128i vlh = _mm_mulhi_epu16(vl, via); + vl = _mm_add_epi32(vll, _mm_slli_epi32(vlh, 16)); +#endif + vl = _mm_add_epi32(vl, vr); + vl = _mm_srli_epi32(vl, 16); + vl = _mm_packs_epi32(vl, _mm_setzero_si128()); + vl = _mm_insert_epi16(vl, alpha, 3); + vl = _mm_packus_epi16(vl, _mm_setzero_si128()); + return _mm_cvtsi128_si32(vl); +} +#else inline QRgb qUnpremultiply(QRgb p) { const uint alpha = qAlpha(p); // Alpha 255 and 0 are the two most common values, which makes them beneficial to short-cut. - if (alpha == 255) + if (alpha == 255 || alpha == 0) return p; - if (alpha == 0) - return 0; // (p*(0x00ff00ff/alpha)) >> 16 == (p*255)/alpha for all p and alpha <= 256. const uint invAlpha = qt_inv_premul_factor[alpha]; // We add 0x8000 to get even rounding. The rounding also ensures that qPremultiply(qUnpremultiply(p)) == p for all p. return qRgba((qRed(p)*invAlpha + 0x8000)>>16, (qGreen(p)*invAlpha + 0x8000)>>16, (qBlue(p)*invAlpha + 0x8000)>>16, alpha); } +#endif QT_END_NAMESPACE -- cgit v1.2.3 From 1b5f29e28a7022f6cde5232eaad2e8f73bc7ffcc Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 4 Apr 2015 21:28:59 +0200 Subject: Remove where it's not used To avoid source-incompatibilites, wrap in QT_DEPRECATED_SINCE(5, 5) in public headers. Change-Id: I6117e8a6b11200d2f1a0a94a0e87d5c27538218e Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/gui/painting/qpaintengine_raster.cpp | 1 - src/gui/painting/qpainter_p.h | 1 - 2 files changed, 2 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 3be6e0f1f4..882a088d5c 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -42,7 +42,6 @@ #include #include -#include #include #include diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 7c32dc1694..3ea4e35b8d 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -53,7 +53,6 @@ #include "QtGui/qpainter.h" #include "QtGui/qpainterpath.h" #include "QtGui/qpaintengine.h" -#include #include -- cgit v1.2.3 From 05d16937935ff830c3266c4a8566feed7fe33dbf Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 8 Apr 2015 19:44:48 +0200 Subject: Add qHash(QMatrix) and qHash(QTransform) QMatrix and QTransform can be compared for equality, so qHash should be overloaded, too. [ChangeLog][QtCore][QMatrix] Added qHash(QMatrix). [ChangeLog][QtCore][QTransform] Added qHash(QTransform). Change-Id: I1ce925ebe258c9d7e35b68e5ac5c3373f1460c58 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/gui/painting/qmatrix.cpp | 24 +++++++++++++++++++++++- src/gui/painting/qmatrix.h | 2 ++ src/gui/painting/qtransform.cpp | 24 ++++++++++++++++++++++++ src/gui/painting/qtransform.h | 2 ++ 4 files changed, 51 insertions(+), 1 deletion(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qmatrix.cpp b/src/gui/painting/qmatrix.cpp index acedc6a7ba..e4d756c18d 100644 --- a/src/gui/painting/qmatrix.cpp +++ b/src/gui/painting/qmatrix.cpp @@ -31,9 +31,11 @@ ** ****************************************************************************/ +#include "qmatrix.h" + #include "qdatastream.h" #include "qdebug.h" -#include "qmatrix.h" +#include "qhashfunctions.h" #include "qregion.h" #include "qpainterpath.h" #include "qpainterpath_p.h" @@ -972,6 +974,26 @@ bool QMatrix::operator==(const QMatrix &m) const _dy == m._dy; } + +/*! + \since 5.6 + \relates QMatrix + + Returns the hash value for \a key, using + \a seed to seed the calculation. +*/ +uint qHash(const QMatrix &key, uint seed) Q_DECL_NOTHROW +{ + QtPrivate::QHashCombine hash; + seed = hash(key.m11(), seed); + seed = hash(key.m12(), seed); + seed = hash(key.m21(), seed); + seed = hash(key.m22(), seed); + seed = hash(key.dx(), seed); + seed = hash(key.dy(), seed); + return seed; +} + /*! \fn bool QMatrix::operator!=(const QMatrix &matrix) const diff --git a/src/gui/painting/qmatrix.h b/src/gui/painting/qmatrix.h index ddffa8a8b9..c036e4df93 100644 --- a/src/gui/painting/qmatrix.h +++ b/src/gui/painting/qmatrix.h @@ -126,6 +126,8 @@ private: }; Q_DECLARE_TYPEINFO(QMatrix, Q_MOVABLE_TYPE); +Q_GUI_EXPORT Q_DECL_CONST_FUNCTION uint qHash(const QMatrix &key, uint seed = 0) Q_DECL_NOTHROW; + // mathematical semantics inline QPoint operator*(const QPoint &p, const QMatrix &m) { return m.map(p); } diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index 31d7a2300b..4b3f0b30dc 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -34,6 +34,7 @@ #include "qdatastream.h" #include "qdebug.h" +#include "qhashfunctions.h" #include "qmatrix.h" #include "qregion.h" #include "qpainterpath.h" @@ -775,6 +776,29 @@ bool QTransform::operator==(const QTransform &o) const m_33 == o.m_33; } +/*! + \since 5.6 + \relates QTransform + + Returns the hash value for \a key, using + \a seed to seed the calculation. +*/ +uint qHash(const QTransform &key, uint seed) Q_DECL_NOTHROW +{ + QtPrivate::QHashCombine hash; + seed = hash(key.m11(), seed); + seed = hash(key.m12(), seed); + seed = hash(key.m21(), seed); + seed = hash(key.m22(), seed); + seed = hash(key.dx(), seed); + seed = hash(key.dy(), seed); + seed = hash(key.m13(), seed); + seed = hash(key.m23(), seed); + seed = hash(key.m33(), seed); + return seed; +} + + /*! \fn bool QTransform::operator!=(const QTransform &matrix) const Returns \c true if this matrix is not equal to the given \a matrix, diff --git a/src/gui/painting/qtransform.h b/src/gui/painting/qtransform.h index cf8d4d1970..65f543144d 100644 --- a/src/gui/painting/qtransform.h +++ b/src/gui/painting/qtransform.h @@ -180,6 +180,8 @@ private: }; Q_DECLARE_TYPEINFO(QTransform, Q_MOVABLE_TYPE); +Q_GUI_EXPORT Q_DECL_CONST_FUNCTION uint qHash(const QTransform &key, uint seed = 0) Q_DECL_NOTHROW; + /******* inlines *****/ inline QTransform::TransformationType QTransform::inline_type() const { -- cgit v1.2.3 From b31e98d477b5bc6a44b96ca1ea73c748e2fbb791 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Sun, 19 Apr 2015 01:07:51 +0200 Subject: Don't use anonymous types declared in an anonymous union At least clang is unhappy with them when -Wnested-anon-types is enabled. Change-Id: Ia9869fecb836b27be69f7b9715fd614f384bb912 Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/qrgba64.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qrgba64.h b/src/gui/painting/qrgba64.h index 51ce4ab10d..5316e32c57 100644 --- a/src/gui/painting/qrgba64.h +++ b/src/gui/painting/qrgba64.h @@ -40,13 +40,15 @@ QT_BEGIN_NAMESPACE class QRgba64 { + struct qrgba_t { + quint16 red; + quint16 green; + quint16 blue; + quint16 alpha; + }; + union { - struct { - quint16 red; - quint16 green; - quint16 blue; - quint16 alpha; - } c; + struct qrgba_t c; quint64 rgba; }; public: -- cgit v1.2.3 From 63d5a42b59149bfdebc9a5a123e7115a813bcaa4 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 22 Apr 2015 19:22:26 +0000 Subject: Revert "Remove separate SSE4 unpremultiply function" Could causedSSE4 instructions to be used on non SSE4 machines in cases when qUnpremultiplywas not inlined. This reverts commit 964ccc58534aac436529007000d1c38d76c88834. Change-Id: Ic676ade8f75129e8d37c4d96cbfb2bdb5b794919 Task-number: QTBUG-45741 Reviewed-by: Thiago Macieira --- src/gui/painting/qdrawhelper.cpp | 10 ++++---- src/gui/painting/qdrawhelper_sse4.cpp | 7 +++--- src/gui/painting/qdrawingprimitive_sse2_p.h | 21 ++++++++++++++++ src/gui/painting/qrgb.h | 37 +++-------------------------- 4 files changed, 34 insertions(+), 41 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 2817a4a145..37f2de98b6 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -6704,22 +6704,24 @@ void qInitDrawhelperAsm() } #endif // SSSE3 -#if defined(QT_COMPILER_SUPPORTS_SSE4_1) && !defined(__SSE4_1__) +#if QT_COMPILER_SUPPORTS_SSE4_1 if (qCpuHasFeature(SSE4_1)) { +#if !defined(__SSE4_1__) extern const uint *QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); extern const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); + qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4; + qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_sse4; +#endif extern const uint *QT_FASTCALL convertARGB32FromARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); extern const uint *QT_FASTCALL convertRGBA8888FromARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); extern const uint *QT_FASTCALL convertRGBXFromARGB32PM_sse4(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); - qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4; - qPixelLayouts[QImage::Format_RGBA8888].convertToARGB32PM = convertRGBA8888ToARGB32PM_sse4; qPixelLayouts[QImage::Format_ARGB32].convertFromARGB32PM = convertARGB32FromARGB32PM_sse4; qPixelLayouts[QImage::Format_RGBA8888].convertFromARGB32PM = convertRGBA8888FromARGB32PM_sse4; qPixelLayouts[QImage::Format_RGBX8888].convertFromARGB32PM = convertRGBXFromARGB32PM_sse4; } #endif -#if defined(QT_COMPILER_SUPPORTS_AVX2) && !defined(__AVX2__) +#if QT_COMPILER_SUPPORTS_AVX2 && !defined(__AVX2__) if (qCpuHasFeature(AVX2)) { extern const uint *QT_FASTCALL convertARGB32ToARGB32PM_avx2(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); extern const uint *QT_FASTCALL convertRGBA8888ToARGB32PM_avx2(uint *buffer, const uint *src, int count, const QPixelLayout *, const QRgb *); diff --git a/src/gui/painting/qdrawhelper_sse4.cpp b/src/gui/painting/qdrawhelper_sse4.cpp index 8e0b2cbb18..43a3958997 100644 --- a/src/gui/painting/qdrawhelper_sse4.cpp +++ b/src/gui/painting/qdrawhelper_sse4.cpp @@ -32,6 +32,7 @@ ****************************************************************************/ #include +#include #if defined(QT_COMPILER_SUPPORTS_SSE4_1) @@ -53,7 +54,7 @@ const uint *QT_FASTCALL convertARGB32FromARGB32PM_sse4(uint *buffer, const uint const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = qUnpremultiply(src[i]); + buffer[i] = qUnpremultiply_sse4(src[i]); return buffer; } @@ -61,7 +62,7 @@ const uint *QT_FASTCALL convertRGBA8888FromARGB32PM_sse4(uint *buffer, const uin const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(qUnpremultiply(src[i])); + buffer[i] = ARGB2RGBA(qUnpremultiply_sse4(src[i])); return buffer; } @@ -69,7 +70,7 @@ const uint *QT_FASTCALL convertRGBXFromARGB32PM_sse4(uint *buffer, const uint *s const QPixelLayout *, const QRgb *) { for (int i = 0; i < count; ++i) - buffer[i] = ARGB2RGBA(0xff000000 | qUnpremultiply(src[i])); + buffer[i] = ARGB2RGBA(0xff000000 | qUnpremultiply_sse4(src[i])); return buffer; } diff --git a/src/gui/painting/qdrawingprimitive_sse2_p.h b/src/gui/painting/qdrawingprimitive_sse2_p.h index fbee06e157..4d0790a502 100644 --- a/src/gui/painting/qdrawingprimitive_sse2_p.h +++ b/src/gui/painting/qdrawingprimitive_sse2_p.h @@ -236,4 +236,25 @@ QT_END_NAMESPACE #endif // __SSE2__ +QT_BEGIN_NAMESPACE +#if QT_COMPILER_SUPPORTS_HERE(SSE4_1) +QT_FUNCTION_TARGET(SSE4_1) +inline QRgb qUnpremultiply_sse4(QRgb p) +{ + const uint alpha = qAlpha(p); + const uint invAlpha = qt_inv_premul_factor[alpha]; + const __m128i via = _mm_set1_epi32(invAlpha); + const __m128i vr = _mm_set1_epi32(0x8000); + __m128i vl = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(p)); + vl = _mm_mullo_epi32(vl, via); + vl = _mm_add_epi32(vl, vr); + vl = _mm_srai_epi32(vl, 16); + vl = _mm_insert_epi32(vl, alpha, 3); + vl = _mm_packus_epi32(vl, _mm_setzero_si128()); + vl = _mm_packus_epi16(vl, _mm_setzero_si128()); + return _mm_cvtsi128_si32(vl); +} +#endif +QT_END_NAMESPACE + #endif // QDRAWINGPRIMITIVE_SSE2_P_H diff --git a/src/gui/painting/qrgb.h b/src/gui/painting/qrgb.h index 05b3a76bce..f7f2185bef 100644 --- a/src/gui/painting/qrgb.h +++ b/src/gui/painting/qrgb.h @@ -36,11 +36,6 @@ #include #include -#if defined(__SSE4_1__) -#include -#elif defined(__SSE2__) -#include -#endif QT_BEGIN_NAMESPACE @@ -92,45 +87,19 @@ inline Q_DECL_RELAXED_CONSTEXPR QRgb qPremultiply(QRgb x) Q_GUI_EXPORT extern const uint qt_inv_premul_factor[]; -#if defined(__SSE2__) -inline QRgb qUnpremultiply(QRgb p) -{ - const uint alpha = qAlpha(p); - if (alpha == 255 || alpha == 0) - return p; - const uint invAlpha = qt_inv_premul_factor[alpha]; - const __m128i via = _mm_set1_epi32(invAlpha); - const __m128i vr = _mm_set1_epi32(0x8000); -#ifdef __SSE4_1__ - __m128i vl = _mm_cvtepu8_epi32(_mm_cvtsi32_si128(p)); - vl = _mm_mullo_epi32(vl, via); -#else - __m128i vl = _mm_unpacklo_epi8(_mm_cvtsi32_si128(p), _mm_setzero_si128()); - vl = _mm_unpacklo_epi16(vl, vl); - __m128i vll = _mm_mullo_epi16(vl, via); - __m128i vlh = _mm_mulhi_epu16(vl, via); - vl = _mm_add_epi32(vll, _mm_slli_epi32(vlh, 16)); -#endif - vl = _mm_add_epi32(vl, vr); - vl = _mm_srli_epi32(vl, 16); - vl = _mm_packs_epi32(vl, _mm_setzero_si128()); - vl = _mm_insert_epi16(vl, alpha, 3); - vl = _mm_packus_epi16(vl, _mm_setzero_si128()); - return _mm_cvtsi128_si32(vl); -} -#else inline QRgb qUnpremultiply(QRgb p) { const uint alpha = qAlpha(p); // Alpha 255 and 0 are the two most common values, which makes them beneficial to short-cut. - if (alpha == 255 || alpha == 0) + if (alpha == 255) return p; + if (alpha == 0) + return 0; // (p*(0x00ff00ff/alpha)) >> 16 == (p*255)/alpha for all p and alpha <= 256. const uint invAlpha = qt_inv_premul_factor[alpha]; // We add 0x8000 to get even rounding. The rounding also ensures that qPremultiply(qUnpremultiply(p)) == p for all p. return qRgba((qRed(p)*invAlpha + 0x8000)>>16, (qGreen(p)*invAlpha + 0x8000)>>16, (qBlue(p)*invAlpha + 0x8000)>>16, alpha); } -#endif QT_END_NAMESPACE -- cgit v1.2.3 From bc162382e5aef0b796582340beb866fb7c55a289 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Thu, 23 Apr 2015 15:31:28 +0200 Subject: Short-cut SSE4 unpremultiply Even with SSE4 optimized unpremultiply it is still significantly faster to skip the calculation on alpha values 0 and 255. Change-Id: Iafe658fea8eacf35a857f292952b0c1ee056139c Reviewed-by: Gunnar Sletta --- src/gui/painting/qdrawingprimitive_sse2_p.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qdrawingprimitive_sse2_p.h b/src/gui/painting/qdrawingprimitive_sse2_p.h index 4d0790a502..1a7dddf0d5 100644 --- a/src/gui/painting/qdrawingprimitive_sse2_p.h +++ b/src/gui/painting/qdrawingprimitive_sse2_p.h @@ -242,6 +242,8 @@ QT_FUNCTION_TARGET(SSE4_1) inline QRgb qUnpremultiply_sse4(QRgb p) { const uint alpha = qAlpha(p); + if (alpha == 255 || alpha == 0) + return p; const uint invAlpha = qt_inv_premul_factor[alpha]; const __m128i via = _mm_set1_epi32(invAlpha); const __m128i vr = _mm_set1_epi32(0x8000); @@ -250,8 +252,8 @@ inline QRgb qUnpremultiply_sse4(QRgb p) vl = _mm_add_epi32(vl, vr); vl = _mm_srai_epi32(vl, 16); vl = _mm_insert_epi32(vl, alpha, 3); - vl = _mm_packus_epi32(vl, _mm_setzero_si128()); - vl = _mm_packus_epi16(vl, _mm_setzero_si128()); + vl = _mm_packus_epi32(vl, vl); + vl = _mm_packus_epi16(vl, vl); return _mm_cvtsi128_si32(vl); } #endif -- cgit v1.2.3 From 57a010adf41c163ff1aa66ad35d28e6f265ee7e0 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 25 Apr 2015 22:42:55 +0200 Subject: Mark QRGba64 as Q_PRIMITIVE_TYPE Change-Id: I1ab25a7b880b47f616ae152400c1e2116688ec4c Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/gui/painting/qrgba64.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qrgba64.h b/src/gui/painting/qrgba64.h index 5316e32c57..290501047d 100644 --- a/src/gui/painting/qrgba64.h +++ b/src/gui/painting/qrgba64.h @@ -169,6 +169,8 @@ private: } }; +Q_DECLARE_TYPEINFO(QRgba64, Q_PRIMITIVE_TYPE); + Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a) { return QRgba64::fromRgba64(r, g, b, a); -- cgit v1.2.3