gdk: add i386 MMX pixel compositing

This commit is contained in:
Daemonratte 2026-08-12 10:07:39 +02:00
commit ed405c407b
6 changed files with 189 additions and 4 deletions

View file

@ -199,6 +199,22 @@ esac
dnl Initialize libtool
AC_PROG_CC
GDK_PIXELOPS_X86_MMX_CFLAGS=
case "$host_cpu:$gdk_pixelops_arch" in
i?86:x86)
GDK_PIXELOPS_X86_MMX_CFLAGS="-mmmx -mno-sse -mno-sse2 -mno-3dnow"
AC_DEFINE([HAVE_GDK_PIXELOPS_X86_MMX], [1],
[Define if the GDK 32-bit x86 MMX pixel operations backend is built])
AC_DEFINE([HAVE_GDK_PIXELOPS_INIT], [1],
[Define if GDK pixel operations require runtime dispatch initialization])
;;
esac
AC_SUBST(GDK_PIXELOPS_X86_MMX_CFLAGS)
AM_CONDITIONAL(GDK_PIXELOPS_X86_MMX,
test -n "$GDK_PIXELOPS_X86_MMX_CFLAGS")
dnl
dnl Check for a working C++ compiler, but do not bail out, if none is found.
dnl We use this for an automated test for C++ header correctness.

View file

@ -14,6 +14,8 @@ DIST_SUBDIRS = win32 x11 quartz directfb tests
CLEANFILES =
noinst_LTLIBRARIES =
EXTRA_DIST += \
keynames.txt \
keyname-table.h \
@ -120,11 +122,22 @@ gdk_private_headers = \
gdkregion-generic.h
gdk_pixelops_arch_sources =
gdk_pixelops_arch_libs =
if GDK_PIXELOPS_X86
gdk_pixelops_arch_sources += gdkpixelops-x86.c
endif
if GDK_PIXELOPS_X86_MMX
noinst_LTLIBRARIES += libgdk-pixelops-x86-mmx.la
gdk_pixelops_arch_libs += libgdk-pixelops-x86-mmx.la
libgdk_pixelops_x86_mmx_la_SOURCES = gdkpixelops-x86-mmx.c
libgdk_pixelops_x86_mmx_la_CFLAGS = \
$(AM_CFLAGS) \
$(GDK_PIXELOPS_X86_MMX_CFLAGS)
endif
gdk_pixelops_private_sources = \
gdkpixelops-generic.c \
$(gdk_pixelops_arch_sources)
@ -188,19 +201,19 @@ common_sources = \
gdkmarshalers.h
libgdk_directfb_2_0_la_SOURCES = $(common_sources)
libgdk_directfb_2_0_la_LIBADD = directfb/libgdk-directfb.la $(GDK_DEP_LIBS)
libgdk_directfb_2_0_la_LIBADD = directfb/libgdk-directfb.la $(gdk_pixelops_arch_libs) $(GDK_DEP_LIBS)
libgdk_directfb_2_0_la_LDFLAGS = $(LDADD)
libgdk_x11_2_0_la_SOURCES = $(common_sources)
libgdk_x11_2_0_la_LIBADD = x11/libgdk-x11.la $(GDK_DEP_LIBS)
libgdk_x11_2_0_la_LIBADD = x11/libgdk-x11.la $(gdk_pixelops_arch_libs) $(GDK_DEP_LIBS)
libgdk_x11_2_0_la_LDFLAGS = $(LDADD)
libgdk_quartz_2_0_la_SOURCES = $(common_sources) gdkkeynames.c
libgdk_quartz_2_0_la_LIBADD = quartz/libgdk-quartz.la $(GDK_DEP_LIBS)
libgdk_quartz_2_0_la_LIBADD = quartz/libgdk-quartz.la $(gdk_pixelops_arch_libs) $(GDK_DEP_LIBS)
libgdk_quartz_2_0_la_LDFLAGS = $(LDADD)
libgdk_win32_2_0_la_SOURCES = $(common_sources) gdkkeynames.c
libgdk_win32_2_0_la_LIBADD = win32/libgdk-win32.la $(GDK_DEP_LIBS)
libgdk_win32_2_0_la_LIBADD = win32/libgdk-win32.la $(gdk_pixelops_arch_libs) $(GDK_DEP_LIBS)
libgdk_win32_2_0_la_DEPENDENCIES = win32/libgdk-win32.la win32/rc/gdk-win32-res.o gdk.def
libgdk_win32_2_0_la_LDFLAGS = -Wl,win32/rc/gdk-win32-res.o -export-symbols $(srcdir)/gdk.def $(LDADD)

View file

@ -32,6 +32,7 @@
#include "gdk.h"
#include "gdkinternals.h"
#include "gdkintl.h"
#include "gdkpixelops.h"
#ifndef HAVE_XCONVERTCASE
#include "gdkkeysyms.h"
@ -189,6 +190,8 @@ gdk_pre_parse_libgtk_only (void)
{
gdk_initialized = TRUE;
_gdk_pixel_ops_init ();
/* We set the fallback program class here, rather than lazily in
* gdk_get_program_class, since we don't want -name to override it.
*/

116
gdk/gdkpixelops-x86-mmx.c Normal file
View file

@ -0,0 +1,116 @@
/* GDK - The GIMP Drawing Kit
*
* MMX pixel operations for 32-bit x86.
*/
#include "config.h"
#include <string.h>
#include <mmintrin.h>
#include "gdkpixelops.h"
#ifndef __i386__
#error "gdkpixelops-x86-mmx.c requires a 32-bit x86 target"
#endif
G_GNUC_INTERNAL void
_gdk_pixel_ops_composite_0888_generic (guchar *src_buf,
gint src_rowstride,
guchar *dest_buf,
gint dest_rowstride,
GdkByteOrder dest_byte_order,
gint width,
gint height);
G_GNUC_INTERNAL void
_gdk_pixel_ops_composite_0888_mmx (guchar *src_buf,
gint src_rowstride,
guchar *dest_buf,
gint dest_rowstride,
GdkByteOrder dest_byte_order,
gint width,
gint height)
{
if (dest_byte_order != GDK_LSB_FIRST)
{
_gdk_pixel_ops_composite_0888_generic (src_buf,
src_rowstride,
dest_buf,
dest_rowstride,
dest_byte_order,
width,
height);
return;
}
{
const __m64 zero = _mm_setzero_si64 ();
const __m64 ones = _mm_cmpeq_pi16 (zero, zero);
const __m64 ff = _mm_srli_pi16 (ones, 8);
const __m64 bias = _mm_set1_pi16 (0x80);
const __m64 rgb_mask = _mm_srli_si64 (ones, 16);
guchar *src = src_buf;
guchar *dest = dest_buf;
while (height--)
{
gint twidth = width;
guchar *p = src;
guchar *q = dest;
while (twidth--)
{
guint32 sp;
guint32 dp;
guint32 result;
__m64 s;
__m64 d;
__m64 a;
__m64 ia;
__m64 t;
__m64 packed;
memcpy (&sp, p, sizeof sp);
memcpy (&dp, q, sizeof dp);
sp = ((sp & 0xff00ff00U) |
((sp & 0x000000ffU) << 16) |
((sp & 0x00ff0000U) >> 16));
s = _mm_cvtsi32_si64 ((int) sp);
d = _mm_cvtsi32_si64 ((int) dp);
s = _mm_unpacklo_pi8 (s, zero);
d = _mm_unpacklo_pi8 (d, zero);
a = _mm_srli_si64 (s, 48);
a = _mm_unpacklo_pi16 (a, a);
a = _mm_unpacklo_pi32 (a, a);
a = _mm_and_si64 (a, rgb_mask);
ia = _mm_sub_pi16 (ff, a);
t = _mm_add_pi16 (_mm_mullo_pi16 (s, a),
_mm_mullo_pi16 (d, ia));
t = _mm_add_pi16 (t, bias);
t = _mm_add_pi16 (t, _mm_srli_pi16 (t, 8));
t = _mm_srli_pi16 (t, 8);
packed = _mm_packs_pu16 (t, t);
result = (guint32) _mm_cvtsi64_si32 (packed);
memcpy (q, &result, sizeof result);
p += 4;
q += 4;
}
src += src_rowstride;
dest += dest_rowstride;
}
_mm_empty ();
}
}

View file

@ -7,7 +7,38 @@
#include "config.h"
#include "gdkpixelops.h"
#if !defined(__i386__) && !defined(__x86_64__) && \
!defined(_M_IX86) && !defined(_M_X64)
#error "gdkpixelops-x86.c must only be built for an x86 target"
#endif
#ifdef HAVE_GDK_PIXELOPS_X86_MMX
#include <cpuid.h>
G_GNUC_INTERNAL void
_gdk_pixel_ops_composite_0888_mmx (guchar *src_buf,
gint src_rowstride,
guchar *dest_buf,
gint dest_rowstride,
GdkByteOrder dest_byte_order,
gint width,
gint height);
G_GNUC_INTERNAL void
_gdk_pixel_ops_init (void)
{
unsigned int eax;
unsigned int ebx;
unsigned int ecx;
unsigned int edx;
if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) &&
(edx & bit_MMX) != 0)
_gdk_pixel_ops.composite_0888 =
_gdk_pixel_ops_composite_0888_mmx;
}
#endif /* HAVE_GDK_PIXELOPS_X86_MMX */

View file

@ -26,6 +26,12 @@ typedef struct
extern G_GNUC_INTERNAL GdkPixelOps _gdk_pixel_ops;
#ifdef HAVE_GDK_PIXELOPS_INIT
G_GNUC_INTERNAL void _gdk_pixel_ops_init (void);
#else
#define _gdk_pixel_ops_init() ((void) 0)
#endif
G_END_DECLS
#endif /* __GDK_PIXEL_OPS_H__ */