/*
 
 SDL_imageFilter - bytes-image "filter" routines 
 (uses inline x86 MMX optimizations if available)
 
 LGPL (c) A. Schiffler

 Note: Most MMX code is based on published routines 
 by Vladimir Kravtchenko at vk@cs.ubc.ca - credits to 
 him for his work.

*/

#include <stdio.h>
#include <stdlib.h>

#include "SDL_imageFilter.h"

#define swap_32(x) (((x) >> 24) | (((x) & 0x00ff0000) >> 8)  | (((x) & 0x0000ff00) << 8)  | ((x) << 24))

/* ------ Static variables ----- */

/* Toggle the use of the MMX routines - ON by default */

static int SDL_imageFilterUseMMX = 1;

/* MMX detection routine (with override flag) */

unsigned int cpuFlags()
{
    int flags = 0;

#ifdef USE_MMX
    asm volatile ("pusha		     \n\t" "mov    %1, %%eax     \n\t"	/* request feature flag */
		  "cpuid                \n\t"	/* get CPU ID flag */
		  "mov    %%edx, %0     \n\t"	/* move result to mmx_bit */
		  "popa		     \n\t":"=m" (flags)	/* %0 */
		  :"i"(0x00000001)	/* %1 */
	);
#endif

    return (flags);
}

int SDL_imageFilterMMXdetect(void)
{
    unsigned int mmx_bit;

    /* Check override flag */
    if (SDL_imageFilterUseMMX == 0) {
	return (0);
    }

    mmx_bit = cpuFlags();
    mmx_bit &= 0x00800000;
    mmx_bit = (mmx_bit && 0x00800000);

    return (mmx_bit);
}

void SDL_imageFilterMMXoff()
{
    SDL_imageFilterUseMMX = 0;
}

void SDL_imageFilterMMXon()
{
    SDL_imageFilterUseMMX = 1;
}

/* ------------------------------------------------------------------------------------ */

/*  SDL_imageFilterAdd: D = saturation255(S1 + S2) */
int SDL_imageFilterAddMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "mov          %2, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %1, %%ebx \n\t"	/* load Src2 address into ebx */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
       "mov          %3, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L1010:                \n\t" "movq    (%%eax), %%mm1 \n\t"	/* load 8 bytes from Src1 into mm1 */
      "paddusb (%%ebx), %%mm1 \n\t"	/* mm1=Src1+Src2 (add 8 bytes with saturation) */
      "movq    %%mm1, (%%edi) \n\t"	/* store result in Dest */
       "add          $8, %%eax \n\t"	/* increase Src1, Src2 and Dest  */
      "add          $8, %%ebx \n\t"	/* register pointers by 8 */
      "add          $8, %%edi \n\t" "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L1010 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src2),		/* %1 */
      "m"(Src1),		/* %2 */
      "m"(length)		/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterAdd: D = saturation255(S1 + S2) */
int SDL_imageFilterAdd(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *cursrc2, *curdst;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	/* Use MMX assembly routine */
	SDL_imageFilterAddMMX(Src1, Src2, Dest, length);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    cursrc2 = &Src2[istart];
	    curdst = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	cursrc2 = Src2;
	curdst = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	result = (int) *cursrc1 + (int) *cursrc2;
	if (result > 255)
	    result = 255;
	*curdst = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	cursrc2++;
	curdst++;
    }

    return (0);
}

/*  SDL_imageFilterMean: D = S1/2 + S2/2 */
int SDL_imageFilterMeanMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length,
			   unsigned char *Mask)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "movl         %4, %%edx \n\t"	/* load Mask address into edx */
      "movq    (%%edx), %%mm0 \n\t"	/* load Mask into mm0 */
       "mov          %2, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %1, %%ebx \n\t"	/* load Src2 address into ebx */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
       "mov          %3, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L21011:                \n\t" 
      "movq    (%%eax), %%mm1 \n\t"	/* load 8 bytes from Src1 into mm1 */
      "movq    (%%ebx), %%mm2 \n\t"	/* load 8 bytes from Src2 into mm2 */
      /* --- Byte shift via Word shift --- */
       "psrlw        $1, %%mm1 \n\t"	/* shift 4 WORDS of mm1 1 bit to the right */
      "psrlw        $1, %%mm2 \n\t"	/* shift 4 WORDS of mm2 1 bit to the right */
/*      "pand      %%mm0, %%mm1 \n\t"    // apply Mask to 8 BYTES of mm1 */
      ".byte     0x0f, 0xdb, 0xc8 \n\t"
/*      "pand      %%mm0, %%mm2 \n\t"    // apply Mask to 8 BYTES of mm2 */
      ".byte     0x0f, 0xdb, 0xd0 \n\t" 
      "paddusb   %%mm2, %%mm1 \n\t"	/* mm1=mm1+mm2 (add 8 bytes with saturation) */
      "movq    %%mm1, (%%edi) \n\t"	/* store result in Dest */
       "add          $8, %%eax \n\t"	/* increase Src1, Src2 and Dest  */
      "add          $8, %%ebx \n\t"	/* register pointers by 8 */
      "add          $8, %%edi \n\t" 
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L21011 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src2),		/* %1 */
      "m"(Src1),		/* %2 */
      "m"(length),		/* %3 */
      "m"(Mask)			/* %4 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterMean: D = S1/2 + S2/2 */
int SDL_imageFilterMean(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
    static unsigned char Mask[8] = { 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F };
    unsigned int i, istart;
    unsigned char *cursrc1, *cursrc2, *curdst;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {
	/* MMX routine */
	SDL_imageFilterMeanMMX(Src1, Src2, Dest, length, Mask);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    cursrc2 = &Src2[istart];
	    curdst = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	cursrc2 = Src2;
	curdst = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	result = (int) *cursrc1 / 2 + (int) *cursrc2 / 2;
	*curdst = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	cursrc2++;
	curdst++;
    }

    return (0);
}

/*  SDL_imageFilterSub: D = saturation0(S1 - S2) */
int SDL_imageFilterSubMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "mov %2, %%eax \n\t"	/* load Src1 address into eax */
      "mov %1, %%ebx \n\t"	/* load Src2 address into ebx */
      "mov %0, %%edi \n\t"	/* load Dest address into edi */
       "mov %3, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16       \n\t"	/* 16 byte allignment of the loop entry */
      ".L1012:         \n\t" "movq    (%%eax), %%mm1 \n\t"	/* load 8 bytes from Src1 into mm1 */
      "psubusb (%%ebx), %%mm1 \n\t"	/* mm1=Src1-Src2 (sub 8 bytes with saturation) */
      "movq    %%mm1, (%%edi) \n\t"	/* store result in Dest */
       "add $8, %%eax \n\t"	/* increase Src1, Src2 and Dest  */
      "add $8, %%ebx \n\t"	/* register pointers by 8 */
      "add $8, %%edi \n\t" "dec %%ecx     \n\t"	/* decrease loop counter */
      "jnz .L1012    \n\t"	/* check loop termination, proceed if required */
       "emms          \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src2),		/* %1 */
      "m"(Src1),		/* %2 */
      "m"(length)		/* %3 */
	);
#endif
    return (0);
}

int SDL_imageFilterSub(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *cursrc2, *curdst;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {
	/* MMX routine */
	SDL_imageFilterSubMMX(Src1, Src2, Dest, length);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    cursrc2 = &Src2[istart];
	    curdst = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	cursrc2 = Src2;
	curdst = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	result = (int) *cursrc1 - (int) *cursrc2;
	if (result < 0)
	    result = 0;
	*curdst = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	cursrc2++;
	curdst++;
    }

    return (0);
}

/*  SDL_imageFilterAbsDiff: D = | S1 - S2 | */
int SDL_imageFilterAbsDiffMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "mov %2, %%eax \n\t"	/* load Src1 address into eax */
      "mov %1, %%ebx \n\t"	/* load Src2 address into ebx */
      "mov %0, %%edi \n\t"	/* load Dest address into edi */
       "mov %3, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16       \n\t"	/* 16 byte allignment of the loop entry */
      ".L1013:         \n\t" "movq    (%%eax), %%mm1 \n\t"	/* load 8 bytes from Src1 into mm1 */
      "movq    (%%ebx), %%mm2 \n\t"	/* load 8 bytes from Src2 into mm2 */
      "psubusb (%%ebx), %%mm1 \n\t"	/* mm1=Src1-Src2 (sub 8 bytes with saturation) */
      "psubusb (%%eax), %%mm2 \n\t"	/* mm2=Src2-Src1 (sub 8 bytes with saturation) */
      "por       %%mm2, %%mm1 \n\t"	/* combine both mm2 and mm1 results */
      "movq    %%mm1, (%%edi) \n\t"	/* store result in Dest */
       "add $8, %%eax \n\t"	/* increase Src1, Src2 and Dest  */
      "add $8, %%ebx \n\t"	/* register pointers by 8 */
      "add $8, %%edi \n\t" "dec %%ecx     \n\t"	/* decrease loop counter */
      "jnz .L1013    \n\t"	/* check loop termination, proceed if required */
       "emms          \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src2),		/* %1 */
      "m"(Src1),		/* %2 */
      "m"(length)		/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterAbsDiff: D = | S1 - S2 | */
int SDL_imageFilterAbsDiff(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *cursrc2, *curdst;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {
	/* MMX routine */
	SDL_imageFilterAbsDiffMMX(Src1, Src2, Dest, length);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    cursrc2 = &Src2[istart];
	    curdst = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	cursrc2 = Src2;
	curdst = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	result = abs((int) *cursrc1 - (int) *cursrc2);
	*curdst = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	cursrc2++;
	curdst++;
    }

    return (0);
}

/*  SDL_imageFilterMult: D = saturation255(S1 * S2) */
int SDL_imageFilterMultMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "mov %2, %%eax \n\t"	/* load Src1 address into eax */
      "mov %1, %%ebx \n\t"	/* load Src2 address into ebx */
      "mov %0, %%edi \n\t"	/* load Dest address into edi */
       "mov %3, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       "pxor      %%mm0, %%mm0 \n\t"	/* zero mm0 register */
       ".align 16       \n\t"	/* 16 byte allignment of the loop entry */
      ".L1014:         \n\t" "movq    (%%eax), %%mm1 \n\t"	/* load 8 bytes from Src1 into mm1 */
      "movq    (%%ebx), %%mm3 \n\t"	/* load 8 bytes from Src2 into mm3 */
      "movq      %%mm1, %%mm2 \n\t"	/* copy mm1 into mm2 */
      "movq      %%mm3, %%mm4 \n\t"	/* copy mm3 into mm4  */
       "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack low  bytes of Src1 into words */
      "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack high bytes of Src1 into words */
      "punpcklbw %%mm0, %%mm3 \n\t"	/* unpack low  bytes of Src2 into words */
      "punpckhbw %%mm0, %%mm4 \n\t"	/* unpack high bytes of Src2 into words */
       "pmullw    %%mm3, %%mm1 \n\t"	/* mul low  bytes of Src1 and Src2  */
      "pmullw    %%mm4, %%mm2 \n\t"	/* mul high bytes of Src1 and Src2 */
      /* Take abs value of the results (signed words) */
       "movq      %%mm1, %%mm5 \n\t"	/* copy mm1 into mm5 */
      "movq      %%mm2, %%mm6 \n\t"	/* copy mm2 into mm6 */
       "psraw       $15, %%mm5 \n\t"	/* fill mm5 words with word sign bit */
      "psraw       $15, %%mm6 \n\t"	/* fill mm6 words with word sign bit */
       "pxor      %%mm5, %%mm1 \n\t"	/* take 1's compliment of only neg. words */
      "pxor      %%mm6, %%mm2 \n\t"	/* take 1's compliment of only neg. words */
       "psubsw    %%mm5, %%mm1 \n\t"	/* add 1 to only neg. words, W-(-1) or W-0 */
      "psubsw    %%mm6, %%mm2 \n\t"	/* add 1 to only neg. words, W-(-1) or W-0 */
       "packuswb  %%mm2, %%mm1 \n\t"	/* pack words back into bytes with saturation */
       "movq    %%mm1, (%%edi) \n\t"	/* store result in Dest */
       "add $8, %%eax \n\t"	/* increase Src1, Src2 and Dest  */
      "add $8, %%ebx \n\t"	/* register pointers by 8 */
      "add $8, %%edi \n\t" "dec %%ecx     \n\t"	/* decrease loop counter */
      "jnz .L1014    \n\t"	/* check loop termination, proceed if required */
       "emms          \n\t"	/* exit MMX state */
      "popa \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src2),		/* %1 */
      "m"(Src1),		/* %2 */
      "m"(length)		/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterMult: D = saturation255(S1 * S2) */
int SDL_imageFilterMult(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *cursrc2, *curdst;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {
	/* MMX routine */
	SDL_imageFilterMultMMX(Src1, Src2, Dest, length);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    cursrc2 = &Src2[istart];
	    curdst = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	cursrc2 = Src2;
	curdst = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {

	/* NOTE: this is probably wrong - dunno what the MMX code does */

	result = (int) *cursrc1 * (int) *cursrc2;
	if (result > 255)
	    result = 255;
	*curdst = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	cursrc2++;
	curdst++;
    }

    return (0);
}

/*  SDL_imageFilterMultNor: D = S1 * S2  (non-MMX) */
int SDL_imageFilterMultNorASM(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "mov %2, %%edx \n\t"	/* load Src1 address into edx */
      "mov %1, %%esi \n\t"	/* load Src2 address into esi */
      "mov %0, %%edi \n\t"	/* load Dest address into edi */
       "mov %3, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
       ".align 16       \n\t"	/* 16 byte allignment of the loop entry */
      ".L10141:        \n\t" "mov  (%%edx), %%al \n\t"	/* load a byte from Src1 */
      "mulb (%%esi)       \n\t"	/* mul with a byte from Src2 */
       ".L10142:           \n\t" "mov %%al, (%%edi)  \n\t"	/* move a byte result to Dest */
       "inc %%edx \n\t"		/* increment Src1, Src2, Dest */
      "inc %%esi \n\t"		/* pointer registers by one */
      "inc %%edi \n\t" "dec %%ecx      \n\t"	/* decrease loop counter */
      "jnz .L10141    \n\t"	/* check loop termination, proceed if required */
       "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src2),		/* %1 */
      "m"(Src1),		/* %2 */
      "m"(length)		/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterMultNor: D = S1 * S2 */
int SDL_imageFilterMultNor(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *cursrc2, *curdst;
    int result;

    if (length > 0) {
	/* ASM routine */
	SDL_imageFilterMultNorASM(Src1, Src2, Dest, length);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    cursrc2 = &Src2[istart];
	    curdst = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* No bytes - we are done */
	return (0);
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	result = (int) *cursrc1 * (int) *cursrc2;
	*curdst = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	cursrc2++;
	curdst++;
    }

    return (0);
}

/*  SDL_imageFilterMultDivby2: D = saturation255(S1/2 * S2) */
int SDL_imageFilterMultDivby2MMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
#ifdef USE_MMX
    asm volatile
     ("pusha \n\t" "mov %2, %%eax \n\t"	/* load Src1 address into eax */
      "mov %1, %%ebx \n\t"	/* load Src2 address into ebx */
      "mov %0, %%edi \n\t"	/* load Dest address into edi */
       "mov %3, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       "pxor      %%mm0, %%mm0 \n\t"	/* zero mm0 register */
       ".align 16       \n\t"	/* 16 byte allignment of the loop entry */
      ".L1015:         \n\t" "movq    (%%eax), %%mm1 \n\t"	/* load 8 bytes from Src1 into mm1 */
      "movq    (%%ebx), %%mm3 \n\t"	/* load 8 bytes from Src2 into mm3 */
      "movq      %%mm1, %%mm2 \n\t"	/* copy mm1 into mm2 */
      "movq      %%mm3, %%mm4 \n\t"	/* copy mm3 into mm4  */
       "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack low  bytes of Src1 into words */
      "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack high bytes of Src1 into words */
      "punpcklbw %%mm0, %%mm3 \n\t"	/* unpack low  bytes of Src2 into words */
      "punpckhbw %%mm0, %%mm4 \n\t"	/* unpack high bytes of Src2 into words */
       "psrlw        $1, %%mm1 \n\t"	/* divide mm1 words by 2, Src1 low bytes */
      "psrlw        $1, %%mm2 \n\t"	/* divide mm2 words by 2, Src1 high bytes */
       "pmullw    %%mm3, %%mm1 \n\t"	/* mul low  bytes of Src1 and Src2  */
      "pmullw    %%mm4, %%mm2 \n\t"	/* mul high bytes of Src1 and Src2 */
       "packuswb  %%mm2, %%mm1 \n\t"	/* pack words back into bytes with saturation */
       "movq    %%mm1, (%%edi) \n\t"	/* store result in Dest */
       "add $8, %%eax \n\t"	/* increase Src1, Src2 and Dest  */
      "add $8, %%ebx \n\t"	/* register pointers by 8 */
      "add $8, %%edi \n\t" "dec %%ecx     \n\t"	/* decrease loop counter */
      "jnz .L1015    \n\t"	/* check loop termination, proceed if required */
       "emms          \n\t"	/* exit MMX state */
      "popa \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src2),		/* %1 */
      "m"(Src1),		/* %2 */
      "m"(length)		/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterMultDivby2: D = saturation255(S1/2 * S2) */
int SDL_imageFilterMultDivby2(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *cursrc2, *curdst;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {
	/* MMX routine */
	SDL_imageFilterMultDivby2MMX(Src1, Src2, Dest, length);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    cursrc2 = &Src2[istart];
	    curdst = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	cursrc2 = Src2;
	curdst = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	result = ((int) *cursrc1 / 2) * (int) *cursrc2;
	if (result > 255)
	    result = 255;
	*curdst = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	cursrc2++;
	curdst++;
    }

    return (0);
}

/*  SDL_imageFilterMultDivby4: D = saturation255(S1/2 * S2/2) */
int SDL_imageFilterMultDivby4MMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "mov %2, %%eax \n\t"	/* load Src1 address into eax */
      "mov %1, %%ebx \n\t"	/* load Src2 address into ebx */
      "mov %0, %%edi \n\t"	/* load Dest address into edi */
       "mov %3, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       "pxor      %%mm0, %%mm0 \n\t"	/* zero mm0 register */
       ".align 16       \n\t"	/* 16 byte allignment of the loop entry */
      ".L1016:         \n\t" "movq    (%%eax), %%mm1 \n\t"	/* load 8 bytes from Src1 into mm1 */
      "movq    (%%ebx), %%mm3 \n\t"	/* load 8 bytes from Src2 into mm3 */
      "movq      %%mm1, %%mm2 \n\t"	/* copy mm1 into mm2 */
      "movq      %%mm3, %%mm4 \n\t"	/* copy mm3 into mm4  */
       "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack low  bytes of Src1 into words */
      "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack high bytes of Src1 into words */
      "punpcklbw %%mm0, %%mm3 \n\t"	/* unpack low  bytes of Src2 into words */
      "punpckhbw %%mm0, %%mm4 \n\t"	/* unpack high bytes of Src2 into words */
       "psrlw        $1, %%mm1 \n\t"	/* divide mm1 words by 2, Src1 low bytes */
      "psrlw        $1, %%mm2 \n\t"	/* divide mm2 words by 2, Src1 high bytes */
      "psrlw        $1, %%mm3 \n\t"	/* divide mm3 words by 2, Src2 low bytes */
      "psrlw        $1, %%mm4 \n\t"	/* divide mm4 words by 2, Src2 high bytes */
       "pmullw    %%mm3, %%mm1 \n\t"	/* mul low  bytes of Src1 and Src2  */
      "pmullw    %%mm4, %%mm2 \n\t"	/* mul high bytes of Src1 and Src2 */
       "packuswb  %%mm2, %%mm1 \n\t"	/* pack words back into bytes with saturation */
       "movq    %%mm1, (%%edi) \n\t"	/* store result in Dest */
       "add $8, %%eax \n\t"	/* increase Src1, Src2 and Dest  */
      "add $8, %%ebx \n\t"	/* register pointers by 8 */
      "add $8, %%edi \n\t" "dec %%ecx     \n\t"	/* decrease loop counter */
      "jnz .L1016    \n\t"	/* check loop termination, proceed if required */
       "emms          \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src2),		/* %1 */
      "m"(Src1),		/* %2 */
      "m"(length)		/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterMultDivby4: D = saturation255(S1/2 * S2/2) */
int SDL_imageFilterMultDivby4(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *cursrc2, *curdst;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {
	/* MMX routine */
	SDL_imageFilterMultDivby4MMX(Src1, Src2, Dest, length);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    cursrc2 = &Src2[istart];
	    curdst = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	cursrc2 = Src2;
	curdst = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	result = ((int) *cursrc1 / 2) * ((int) *cursrc2 / 2);
	if (result > 255)
	    result = 255;
	*curdst = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	cursrc2++;
	curdst++;
    }

    return (0);
}

/*  SDL_imageFilterBitAnd: D = S1 & S2 */
int SDL_imageFilterBitAndMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "mov %2, %%eax \n\t"	/* load Src1 address into eax */
      "mov %1, %%ebx \n\t"	/* load Src2 address into ebx */
      "mov %0, %%edi \n\t"	/* load Dest address into edi */
       "mov %3, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16       \n\t"	/* 16 byte allignment of the loop entry */
      ".L1017:         \n\t" "movq    (%%eax), %%mm1 \n\t"	/* load 8 bytes from Src1 into mm1 */
      "pand    (%%ebx), %%mm1 \n\t"	/* mm1=Src1&Src2 */
      "movq    %%mm1, (%%edi) \n\t"	/* store result in Dest */
       "add $8, %%eax \n\t"	/* increase Src1, Src2 and Dest  */
      "add $8, %%ebx \n\t"	/* register pointers by 8 */
      "add $8, %%edi \n\t" "dec %%ecx     \n\t"	/* decrease loop counter */
      "jnz .L1017    \n\t"	/* check loop termination, proceed if required */
       "emms          \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src2),		/* %1 */
      "m"(Src1),		/* %2 */
      "m"(length)		/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterBitAnd: D = S1 & S2 */
int SDL_imageFilterBitAnd(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *cursrc2, *curdst;

/* if ((SDL_imageFilterMMXdetect()>0) && (length>7)) { */
    if (length > 7) {
	/* Call MMX routine */

	SDL_imageFilterBitAndMMX(Src1, Src2, Dest, length);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {

	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    cursrc2 = &Src2[istart];
	    curdst = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	cursrc2 = Src2;
	curdst = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	*curdst = (*cursrc1) & (*cursrc2);
	/* Advance pointers */
	cursrc1++;
	cursrc2++;
	curdst++;
    }

    return (0);
}

/*  SDL_imageFilterBitOr: D = S1 | S2 */
int SDL_imageFilterBitOrMMX(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "mov %2, %%eax \n\t"	/* load Src1 address into eax */
      "mov %1, %%ebx \n\t"	/* load Src2 address into ebx */
      "mov %0, %%edi \n\t"	/* load Dest address into edi */
       "mov %3, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16       \n\t"	/* 16 byte allignment of the loop entry */
      ".L91017:        \n\t" "movq    (%%eax), %%mm1 \n\t"	/* load 8 bytes from Src1 into mm1 */
      "por     (%%ebx), %%mm1 \n\t"	/* mm1=Src1|Src2 */
      "movq    %%mm1, (%%edi) \n\t"	/* store result in Dest */
       "add $8, %%eax \n\t"	/* increase Src1, Src2 and Dest  */
      "add $8, %%ebx \n\t"	/* register pointers by 8 */
      "add $8, %%edi \n\t" "dec %%ecx     \n\t"	/* decrease loop counter */
      "jnz .L91017   \n\t"	/* check loop termination, proceed if required */
       "emms          \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src2),		/* %1 */
      "m"(Src1),		/* %2 */
      "m"(length)		/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterBitOr: D = S1 | S2 */
int SDL_imageFilterBitOr(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *cursrc2, *curdst;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	/* MMX routine */
	SDL_imageFilterBitOrMMX(Src1, Src2, Dest, length);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    cursrc2 = &Src2[istart];
	    curdst = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	cursrc2 = Src2;
	curdst = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	*curdst = *cursrc1 | *cursrc2;
	/* Advance pointers */
	cursrc1++;
	cursrc2++;
	curdst++;
    }
    return (0);
}

/*  SDL_imageFilterDiv: D = S1 / S2  (non-MMX) */
int SDL_imageFilterDivASM(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
#ifdef USE_MMX
    asm volatile
     ("pusha \n\t" "mov %2, %%edx \n\t"	/* load Src1 address into edx */
      "mov %1, %%esi \n\t"	/* load Src2 address into esi */
      "mov %0, %%edi \n\t"	/* load Dest address into edi */
       "mov %3, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
       ".align 16     \n\t"	/* 16 byte allignment of the loop entry */
      ".L10191:      \n\t" "mov  (%%esi), %%bl  \n\t"	/* load a byte from Src2 */
      "cmp       $0, %%bl  \n\t"	/* check if it zero */
      "jnz .L10192         \n\t" "movb  $255, (%%edi) \n\t"	/* division by zero = 255 !!! */
      "jmp  .L10193        \n\t" ".L10192:            \n\t" "xor   %%ah, %%ah    \n\t"	/* prepare AX, zero AH register */
      "mov   (%%edx), %%al \n\t"	/* load a byte from Src1 into AL */
      "div   %%bl          \n\t"	/* divide AL by BL */
      "mov   %%al, (%%edi) \n\t"	/* move a byte result to Dest */
       ".L10193:            \n\t" "inc %%edx \n\t"	/* increment Src1, Src2, Dest */
      "inc %%esi \n\t"		/* pointer registers by one */
      "inc %%edi \n\t" "dec %%ecx    \n\t"	/* decrease loop counter */
      "jnz .L10191  \n\t"	/* check loop termination, proceed if required */
       "popa \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src2),		/* %1 */
      "m"(Src1),		/* %2 */
      "m"(length)		/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterDiv: D = S1 / S2  (non-MMX!) */
int SDL_imageFilterDiv(unsigned char *Src1, unsigned char *Src2, unsigned char *Dest, int length)
{
    if (length > 0) {
	/* Call ASM routine */
	SDL_imageFilterDivASM(Src1, Src2, Dest, length);

	/* Never unaligned bytes - we are done */
	return (0);
    } else {
	return (-1);
    }
}

/* ------------------------------------------------------------------------------------ */

/*  SDL_imageFilterBitNegation: D = !S */
int SDL_imageFilterBitNegationMMX(unsigned char *Src1, unsigned char *Dest, int length)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "pcmpeqb   %%mm1, %%mm1 \n\t"	/* generate all 1's in mm1 */
       "mov %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov %0, %%edi \n\t"	/* load Dest address into edi */
       "mov %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16       \n\t"	/* 16 byte allignment of the loop entry */
      ".L91117:        \n\t" "movq    (%%eax), %%mm0 \n\t"	/* load 8 bytes from Src1 into mm1 */
      "pxor      %%mm1, %%mm0 \n\t"	/* negate mm0 by xoring with mm1 */
      "movq    %%mm0, (%%edi) \n\t"	/* store result in Dest */
       "add $8, %%eax \n\t"	/* increase Src1, Src2 and Dest  */
      "add $8, %%edi \n\t" "dec %%ecx     \n\t"	/* decrease loop counter */
      "jnz .L91117   \n\t"	/* check loop termination, proceed if required */
       "emms          \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length)		/* %2 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterBitNegation: D = !S */
int SDL_imageFilterBitNegation(unsigned char *Src1, unsigned char *Dest, int length)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *curdst;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {
	/* MMX routine */
	SDL_imageFilterBitNegationMMX(Src1, Dest, length);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdst = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdst = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	*curdst = ~(*cursrc1);
	/* Advance pointers */
	cursrc1++;
	curdst++;
    }

    return (0);
}

/*  SDL_imageFilterAddByteMMX: D = saturation255(S + C) */
int SDL_imageFilterAddByteMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned char C)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t"
      /* ** Duplicate C in 8 bytes of MM1 ** */
      "mov           %3, %%al \n\t"	/* load C into AL */
      "mov         %%al, %%ah \n\t"	/* copy AL into AH */
      "mov         %%ax, %%bx \n\t"	/* copy AX into BX */
      "shl         $16, %%eax \n\t"	/* shift 2 bytes of EAX left */
      "mov         %%bx, %%ax \n\t"	/* copy BX into AX */
      "movd      %%eax, %%mm1 \n\t"	/* copy EAX into MM1 */
      "movd      %%eax, %%mm2 \n\t"	/* copy EAX into MM2 */
      "punpckldq %%mm2, %%mm1 \n\t"	/* fill higher bytes of MM1 with C */
       "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L1021:                \n\t" 
      "movq    (%%eax), %%mm0 \n\t"	/* load 8 bytes from Src1 into MM0 */
      "paddusb   %%mm1, %%mm0 \n\t"	/* MM0=SrcDest+C (add 8 bytes with saturation) */
      "movq    %%mm0, (%%edi) \n\t"	/* store result in Dest */
       "add          $8, %%eax \n\t"	/* increase Dest register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L1021 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(C)			/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterAddByte: D = saturation255(S + C) */
int SDL_imageFilterAddByte(unsigned char *Src1, unsigned char *Dest, int length, unsigned char C)
{
    unsigned int i, istart;
    int iC;
    unsigned char *cursrc1, *curdest;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	/* MMX routine */
	SDL_imageFilterAddByteMMX(Src1, Dest, length, C);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    iC = (int) C;
    for (i = istart; i < length; i++) {
	result = (int) *cursrc1 + iC;
	if (result > 255)
	    result = 255;
	*curdest = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	curdest++;
    }
    return (0);
}

/*  SDL_imageFilterAddUintMMX: D = saturation255((S + (uint)C), Cs=swap_32(C) */
int SDL_imageFilterAddUintMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned int C, unsigned int Cs)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t"
      /* ** Duplicate (int)C in 8 bytes of MM1 ** */
      "mov          %3, %%eax \n\t"	/* load C into EAX */
      "movd      %%eax, %%mm1 \n\t"	/* copy EAX into MM1 */
      "mov          %4, %%eax \n\t"	/* load Cs into EAX */
      "movd      %%eax, %%mm2 \n\t"	/* copy EAX into MM2 */
      "punpckldq %%mm2, %%mm1 \n\t"	/* fill higher bytes of MM1 with C */
      "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L11023:                \n\t" 
      "movq    (%%eax), %%mm0 \n\t"	/* load 8 bytes from SrcDest into MM0 */
      "paddusb   %%mm1, %%mm0 \n\t"	/* MM0=SrcDest+C (add 8 bytes with saturation) */
      "movq    %%mm0, (%%edi) \n\t"	/* store result in SrcDest */
      "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L11023 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(C),			/* %3 */
      "m"(Cs)			/* %4 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterAddUint: D = saturation0(S - (Uint)C) */
int SDL_imageFilterAddUint(unsigned char *Src1, unsigned char *Dest, int length, unsigned int C)
{
    unsigned int i, j, istart, D;
    int iC[4];
    unsigned char *cursrc1;
    unsigned char *curdest;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	/* MMX routine */
	D=swap_32(C);
	SDL_imageFilterAddUintMMX(Src1, Dest, length, C, D);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process bytes */
    iC[0] = (int) ((C >> 24) & 0xff);
    iC[1] = (int) ((C >> 16) & 0xff);
    iC[2] = (int) ((C >>  8) & 0xff);
    iC[3] = (int) ((C >>  0) & 0xff);
    for (i = istart; i < length; i += 4) {
     for (j = 0; j < 4; j++) {
      if ((i+j)<length) {
	result = (int) *cursrc1 + iC[j];
	if (result > 255) result = 255;
	*curdest = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	curdest++;
      }
     }
    }
    return (0);
}


/*  SDL_imageFilterAddByteToHalfMMX: D = saturation255(S/2 + C) */
int SDL_imageFilterAddByteToHalfMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned char C,
				    unsigned char *Mask)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t"
      /* ** Duplicate C in 8 bytes of MM1 ** */
      "mov           %3, %%al \n\t"	/* load C into AL */
      "mov         %%al, %%ah \n\t"	/* copy AL into AH */
      "mov         %%ax, %%bx \n\t"	/* copy AX into BX */
      "shl         $16, %%eax \n\t"	/* shift 2 bytes of EAX left */
      "mov         %%bx, %%ax \n\t"	/* copy BX into AX */
      "movd      %%eax, %%mm1 \n\t"	/* copy EAX into MM1 */
      "movd      %%eax, %%mm2 \n\t"	/* copy EAX into MM2 */
      "punpckldq %%mm2, %%mm1 \n\t"	/* fill higher bytes of MM1 with C */
       "movl         %4, %%edx \n\t"	/* load Mask address into edx */
      "movq    (%%edx), %%mm0 \n\t"	/* load Mask into mm0 */
       "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L1022:                \n\t" 
      "movq    (%%eax), %%mm2 \n\t"	/* load 8 bytes from Src1 into MM2 */
      "psrlw        $1, %%mm2 \n\t"	/* shift 4 WORDS of MM2 1 bit to the right */
      /*    "pand      %%mm0, %%mm2 \n\t"    // apply Mask to 8 BYTES of MM2 */
      ".byte     0x0f, 0xdb, 0xd0 \n\t" 
      "paddusb   %%mm1, %%mm2 \n\t"	/* MM2=SrcDest+C (add 8 bytes with saturation) */
      "movq    %%mm2, (%%edi) \n\t"	/* store result in Dest */
       "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L1022 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(C),			/* %3 */
      "m"(Mask)			/* %4 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterAddByteToHalf: D = saturation255(S/2 + C) */
int SDL_imageFilterAddByteToHalf(unsigned char *Src1, unsigned char *Dest, int length, unsigned char C)
{
    static unsigned char Mask[8] = { 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F };
    unsigned int i, istart;
    int iC;
    unsigned char *cursrc1;
    unsigned char *curdest;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	/* MMX routine */
	SDL_imageFilterAddByteToHalfMMX(Src1, Dest, length, C, Mask);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    iC = (int) C;
    for (i = istart; i < length; i++) {
	result = (int) (*cursrc1 / 2) + iC;
	if (result > 255)
	    result = 255;
	*curdest = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	curdest++;
    }

    return (0);
}

/*  SDL_imageFilterSubByteMMX: D = saturation0(S - C) */
int SDL_imageFilterSubByteMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned char C)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t"
      /* ** Duplicate C in 8 bytes of MM1 ** */
      "mov           %3, %%al \n\t"	/* load C into AL */
      "mov         %%al, %%ah \n\t"	/* copy AL into AH */
      "mov         %%ax, %%bx \n\t"	/* copy AX into BX */
      "shl         $16, %%eax \n\t"	/* shift 2 bytes of EAX left */
      "mov         %%bx, %%ax \n\t"	/* copy BX into AX */
      "movd      %%eax, %%mm1 \n\t"	/* copy EAX into MM1 */
      "movd      %%eax, %%mm2 \n\t"	/* copy EAX into MM2 */
      "punpckldq %%mm2, %%mm1 \n\t"	/* fill higher bytes of MM1 with C */
      "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L1023:                \n\t" "movq    (%%eax), %%mm0 \n\t"	/* load 8 bytes from SrcDest into MM0 */
      "psubusb   %%mm1, %%mm0 \n\t"	/* MM0=SrcDest-C (sub 8 bytes with saturation) */
      "movq    %%mm0, (%%edi) \n\t"	/* store result in SrcDest */
       "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L1023 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(C)			/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterSubByte: D = saturation0(S - C) */
int SDL_imageFilterSubByte(unsigned char *Src1, unsigned char *Dest, int length, unsigned char C)
{
    unsigned int i, istart;
    int iC;
    unsigned char *cursrc1;
    unsigned char *curdest;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	/* MMX routine */
	SDL_imageFilterSubByteMMX(Src1, Dest, length, C);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    iC = (int) C;
    for (i = istart; i < length; i++) {
	result = (int) *cursrc1 - iC;
	if (result < 0)
	    result = 0;
	*curdest = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	curdest++;
    }
    return (0);
}

/*  SDL_imageFilterSubUintMMX: D = saturation0(S - (uint)C), Cs=swap_32(C) */
int SDL_imageFilterSubUintMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned int C, unsigned int Cs)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t"
      /* ** Duplicate (int)C in 8 bytes of MM1 ** */
      "mov          %3, %%eax \n\t"	/* load C into EAX */
      "movd      %%eax, %%mm1 \n\t"	/* copy EAX into MM1 */
      "mov          %4, %%eax \n\t"	/* load Cs into EAX */
      "movd      %%eax, %%mm2 \n\t"	/* copy EAX into MM2 */
      "punpckldq %%mm2, %%mm1 \n\t"	/* fill higher bytes of MM1 with C */
      "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L11024:                \n\t" "movq    (%%eax), %%mm0 \n\t"	/* load 8 bytes from SrcDest into MM0 */
      "psubusb   %%mm1, %%mm0 \n\t"	/* MM0=SrcDest-C (sub 8 bytes with saturation) */
      "movq    %%mm0, (%%edi) \n\t"	/* store result in SrcDest */
       "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L11024 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(C),			/* %3 */
      "m"(Cs)			/* %4 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterSubUint: D = saturation0(S - (Uint)C) */
int SDL_imageFilterSubUint(unsigned char *Src1, unsigned char *Dest, int length, unsigned int C)
{
    unsigned int i, j, istart, D;
    int iC[4];
    unsigned char *cursrc1;
    unsigned char *curdest;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	/* MMX routine */
	D=swap_32(C);
	SDL_imageFilterSubUintMMX(Src1, Dest, length, C, D);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    iC[0] = (int) ((C >> 24) & 0xff);
    iC[1] = (int) ((C >> 16) & 0xff);
    iC[2] = (int) ((C >>  8) & 0xff);
    iC[3] = (int) ((C >>  0) & 0xff);
    for (i = istart; i < length; i += 4) {
     for (j = 0; j < 4; j++) {
      if ((i+j)<length) {
	result = (int) *cursrc1 - iC[j];
	if (result < 0) result = 0;
	*curdest = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	curdest++;
      }
     }
    }
    return (0);
}


/*  SDL_imageFilterShiftRightMMX: D = saturation0(S >> N) */
int SDL_imageFilterShiftRightMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned char N,
				 unsigned char *Mask)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "movl         %4, %%edx \n\t"	/* load Mask address into edx */
      "movq    (%%edx), %%mm0 \n\t"	/* load Mask into mm0 */
       "xor       %%ecx, %%ecx \n\t"	/* zero ECX */
      "mov           %3, %%cl \n\t"	/* load loop counter (N) into CL */
      "movd      %%ecx, %%mm3 \n\t"	/* copy (N) into MM3  */
       "pcmpeqb   %%mm1, %%mm1 \n\t"	/* generate all 1's in mm1 */
       ".L10240:               \n\t"	/* ** Prepare proper bit-Mask in MM1 ** */
       "psrlw        $1, %%mm1 \n\t"	/* shift 4 WORDS of MM1 1 bit to the right */
      /*    "pand      %%mm0, %%mm1 \n\t"    // apply Mask to 8 BYTES of MM1 */
      ".byte     0x0f, 0xdb, 0xc8 \n\t" 
      "dec               %%cl \n\t"	/* decrease loop counter */
      "jnz            .L10240 \n\t"	/* check loop termination, proceed if required */
      /* ** Shift all bytes of the image ** */
       "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L10241:               \n\t" 
      "movq    (%%eax), %%mm0 \n\t"	/* load 8 bytes from SrcDest into MM0 */
      "psrlw     %%mm3, %%mm0 \n\t"	/* shift 4 WORDS of MM0 (N) bits to the right */
      /*    "pand      %%mm1, %%mm0 \n\t"    // apply proper bit-Mask to 8 BYTES of MM0 */
      ".byte     0x0f, 0xdb, 0xc1 \n\t" 
      "movq    %%mm0, (%%edi) \n\t"	/* store result in SrcDest */
      "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz            .L10241 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(N),			/* %3 */
      "m"(Mask)			/* %4 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterShiftRight: D = saturation0(S >> N) */
int SDL_imageFilterShiftRight(unsigned char *Src1, unsigned char *Dest, int length, unsigned char N)
{
    static unsigned char Mask[8] = { 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F };
    unsigned int i, istart;
    unsigned char *cursrc1;
    unsigned char *curdest;

    /* Check shift */
    if ((N > 8) || (N < 1)) {
	return (-1);
    }

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	/* MMX routine */
	SDL_imageFilterShiftRightMMX(Src1, Dest, length, N, Mask);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	*curdest = (unsigned char) *cursrc1 >> N;
	/* Advance pointers */
	cursrc1++;
	curdest++;
    }

    return (0);
}

/*  SDL_imageFilterShiftRightUintMMX: D = Saturation0(S >> N) */
int SDL_imageFilterShiftRightUintMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned char N)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t"
      "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L13023:                \n\t" "movq    (%%eax), %%mm0 \n\t"	/* load 8 bytes from SrcDest into MM0 */
      "psrld   %3, %%mm0 \n\t"
      "movq    %%mm0, (%%edi) \n\t"	/* store result in SrcDest */
      "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L13023 \n\t"	/* check loop termination, proceed if required */
      "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(N)			/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterShiftRightUint: D = Saturation0((uint)S >> N) */
int SDL_imageFilterShiftRightUint(unsigned char *Src1, unsigned char *Dest, int length, unsigned char N)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *curdest;
    unsigned int *icursrc1, *icurdest;
    int result;

    /* min. 1 bit and max. 32 bit shift is allowed */
    if ((N > 32) || (N < 1)) return (-1);

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	SDL_imageFilterShiftRightUintMMX(Src1, Dest, length, N);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    icursrc1=(unsigned int *)cursrc1;
    icurdest=(unsigned int *)curdest;
    for (i = istart; i < length; i += 4) {
     if ((i+4)<length) {
	result = ((unsigned int)*icursrc1 >> N);
	*icurdest = (unsigned int)result;
     }
     /* Advance pointers */
     icursrc1++;
     icurdest++;
    }

    return (0);
}

/*  SDL_imageFilterMultByByteMMX: D = saturation255(S * C) */
int SDL_imageFilterMultByByteMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned char C)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t"
      /* ** Duplicate C in 4 words of MM1 ** */
      "mov           %3, %%al \n\t"	/* load C into AL */
      "xor         %%ah, %%ah \n\t"	/* zero AH */
      "mov         %%ax, %%bx \n\t"	/* copy AX into BX */
      "shl         $16, %%eax \n\t"	/* shift 2 bytes of EAX left */
      "mov         %%bx, %%ax \n\t"	/* copy BX into AX */
      "movd      %%eax, %%mm1 \n\t"	/* copy EAX into MM1 */
      "movd      %%eax, %%mm2 \n\t"	/* copy EAX into MM2 */
      "punpckldq %%mm2, %%mm1 \n\t"	/* fill higher words of MM1 with C */
       "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 register */
       "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       "cmp         $128, %%al \n\t"	/* if (C <= 128) execute more efficient code */
      "jg             .L10251 \n\t" ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L10250:               \n\t" "movq    (%%eax), %%mm3 \n\t"	/* load 8 bytes from Src1 into MM3 */
      "movq      %%mm3, %%mm4 \n\t"	/* copy MM3 into MM4  */
      "punpcklbw %%mm0, %%mm3 \n\t"	/* unpack low  bytes of SrcDest into words */
      "punpckhbw %%mm0, %%mm4 \n\t"	/* unpack high bytes of SrcDest into words */
      "pmullw    %%mm1, %%mm3 \n\t"	/* mul low  bytes of SrcDest and MM1 */
      "pmullw    %%mm1, %%mm4 \n\t"	/* mul high bytes of SrcDest and MM1 */
      "packuswb  %%mm4, %%mm3 \n\t"	/* pack words back into bytes with saturation */
      "movq    %%mm3, (%%edi) \n\t"	/* store result in Dest */
       "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz            .L10250 \n\t"	/* check loop termination, proceed if required */
      "jmp            .L10252 \n\t" ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L10251:               \n\t" "movq    (%%eax), %%mm3 \n\t"	/* load 8 bytes from Src1 into MM3 */
      "movq      %%mm3, %%mm4 \n\t"	/* copy MM3 into MM4  */
      "punpcklbw %%mm0, %%mm3 \n\t"	/* unpack low  bytes of SrcDest into words */
      "punpckhbw %%mm0, %%mm4 \n\t"	/* unpack high bytes of SrcDest into words */
      "pmullw    %%mm1, %%mm3 \n\t"	/* mul low  bytes of SrcDest and MM1 */
      "pmullw    %%mm1, %%mm4 \n\t"	/* mul high bytes of SrcDest and MM1 */
      /* ** Take abs value of the results (signed words) ** */
       "movq      %%mm3, %%mm5 \n\t"	/* copy mm3 into mm5 */
      "movq      %%mm4, %%mm6 \n\t"	/* copy mm4 into mm6 */
      "psraw       $15, %%mm5 \n\t"	/* fill mm5 words with word sign bit */
      "psraw       $15, %%mm6 \n\t"	/* fill mm6 words with word sign bit */
      "pxor      %%mm5, %%mm3 \n\t"	/* take 1's compliment of only neg. words */
      "pxor      %%mm6, %%mm4 \n\t"	/* take 1's compliment of only neg. words */
      "psubsw    %%mm5, %%mm3 \n\t"	/* add 1 to only neg. words, W-(-1) or W-0 */
      "psubsw    %%mm6, %%mm4 \n\t"	/* add 1 to only neg. words, W-(-1) or W-0 */
      "packuswb  %%mm4, %%mm3 \n\t"	/* pack words back into bytes with saturation */
      "movq    %%mm3, (%%edi) \n\t"	/* store result in Dest */
       "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz            .L10251 \n\t"	/* check loop termination, proceed if required */
       ".L10252:               \n\t" "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(C)			/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterMultByByte: D = saturation255(S * C) */
int SDL_imageFilterMultByByte(unsigned char *Src1, unsigned char *Dest, int length, unsigned char C)
{
    unsigned int i, istart;
    int iC;
    unsigned char *cursrc1;
    unsigned char *curdest;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	SDL_imageFilterMultByByteMMX(Src1, Dest, length, C);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    iC = (int) C;
    for (i = istart; i < length; i++) {
	result = (int) *cursrc1 * iC;
	if (result > 255)
	    result = 255;
	*curdest = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	curdest++;
    }

    return (0);
}

/*  SDL_imageFilterShiftRightAndMultByByteMMX: D = saturation255((S >> N) * C) */
int SDL_imageFilterShiftRightAndMultByByteMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned char N,
					      unsigned char C)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t"
      /* ** Duplicate C in 4 words of MM1 ** */
      "mov           %4, %%al \n\t"	/* load C into AL */
      "xor         %%ah, %%ah \n\t"	/* zero AH */
      "mov         %%ax, %%bx \n\t"	/* copy AX into BX */
      "shl         $16, %%eax \n\t"	/* shift 2 bytes of EAX left */
      "mov         %%bx, %%ax \n\t"	/* copy BX into AX */
      "movd      %%eax, %%mm1 \n\t"	/* copy EAX into MM1 */
      "movd      %%eax, %%mm2 \n\t"	/* copy EAX into MM2 */
      "punpckldq %%mm2, %%mm1 \n\t"	/* fill higher words of MM1 with C */
       "xor       %%ecx, %%ecx \n\t"	/* zero ECX */
      "mov           %3, %%cl \n\t"	/* load N into CL */
      "movd      %%ecx, %%mm7 \n\t"	/* copy N into MM7 */
       "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 register */
       "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L1026:                \n\t" "movq    (%%eax), %%mm3 \n\t"	/* load 8 bytes from Src1 into MM3 */
      "movq      %%mm3, %%mm4 \n\t"	/* copy MM3 into MM4  */
      "punpcklbw %%mm0, %%mm3 \n\t"	/* unpack low  bytes of SrcDest into words */
      "punpckhbw %%mm0, %%mm4 \n\t"	/* unpack high bytes of SrcDest into words */
      "psrlw     %%mm7, %%mm3 \n\t"	/* shift 4 WORDS of MM3 (N) bits to the right */
      "psrlw     %%mm7, %%mm4 \n\t"	/* shift 4 WORDS of MM4 (N) bits to the right */
      "pmullw    %%mm1, %%mm3 \n\t"	/* mul low  bytes of SrcDest by MM1 */
      "pmullw    %%mm1, %%mm4 \n\t"	/* mul high bytes of SrcDest by MM1 */
      "packuswb  %%mm4, %%mm3 \n\t"	/* pack words back into bytes with saturation */
      "movq    %%mm3, (%%edi) \n\t"	/* store result in Dest */
       "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L1026 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(N),			/* %3 */
      "m"(C)			/* %4 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterShiftRightAndMultByByte: D = saturation255((S >> N) * C) */
int SDL_imageFilterShiftRightAndMultByByte(unsigned char *Src1, unsigned char *Dest, int length, unsigned char N,
					   unsigned char C)
{
    unsigned int i, istart;
    int iC;
    unsigned char *cursrc1;
    unsigned char *curdest;
    int result;

    /* Check shift */
    if ((N > 8) || (N < 1)) {
	return (-1);
    }

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	SDL_imageFilterShiftRightAndMultByByteMMX(Src1, Dest, length, N, C);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    iC = (int) C;
    for (i = istart; i < length; i++) {
	result = (int) (*cursrc1 >> N) * iC;
	if (result > 255)
	    result = 255;
	*curdest = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	curdest++;
    }

    return (0);
}

/*  SDL_imageFilterShiftLeftByteMMX: D = (S << N) */
int SDL_imageFilterShiftLeftByteMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned char N,
				    unsigned char *Mask)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "movl         %4, %%edx \n\t"	/* load Mask address into edx */
      "movq    (%%edx), %%mm0 \n\t"	/* load Mask into mm0 */
       "xor       %%ecx, %%ecx \n\t"	/* zero ECX */
      "mov           %3, %%cl \n\t"	/* load loop counter (N) into CL */
      "movd      %%ecx, %%mm3 \n\t"	/* copy (N) into MM3  */
       "pcmpeqb   %%mm1, %%mm1 \n\t"	/* generate all 1's in mm1 */
       ".L10270:               \n\t"	/* ** Prepare proper bit-Mask in MM1 ** */
       "psllw        $1, %%mm1 \n\t"	/* shift 4 WORDS of MM1 1 bit to the left */
      /*    "pand      %%mm0, %%mm1 \n\t"    // apply Mask to 8 BYTES of MM1 */
      ".byte     0x0f, 0xdb, 0xc8 \n\t" "dec %%cl               \n\t"	/* decrease loop counter */
      "jnz            .L10270 \n\t"	/* check loop termination, proceed if required */
      /* ** Shift all bytes of the image ** */
       "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load SrcDest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L10271:               \n\t" "movq    (%%eax), %%mm0 \n\t"	/* load 8 bytes from Src1 into MM0 */
      "psllw     %%mm3, %%mm0 \n\t"	/* shift 4 WORDS of MM0 (N) bits to the left */
      /*    "pand      %%mm1, %%mm0 \n\t"    // apply proper bit-Mask to 8 BYTES of MM0 */
      ".byte     0x0f, 0xdb, 0xc1 \n\t" "movq    %%mm0, (%%edi) \n\t"	/* store result in Dest */
       "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz            .L10271 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(N),			/* %3 */
      "m"(Mask)			/* %4 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterShiftLeftByte: D = (S << N) */
int SDL_imageFilterShiftLeftByte(unsigned char *Src1, unsigned char *Dest, int length, unsigned char N)
{
    static unsigned char Mask[8] = { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE };
    unsigned int i, istart;
    unsigned char *cursrc1, *curdest;
    int result;

    if ((N > 8) || (N < 1))
	return (-1);		/* image size must be at least 8 bytes  */
    /* and min. 1 bit and max. 8 bit shift is allowed */

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	SDL_imageFilterShiftLeftByteMMX(Src1, Dest, length, N, Mask);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	result = ((int) *cursrc1 << N) & 0xff;
	*curdest = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	curdest++;
    }

    return (0);
}

/*  SDL_imageFilterShiftLeftUintMMX: D = (S << N) */
int SDL_imageFilterShiftLeftUintMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned char N)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t"
      "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L12023:                \n\t" "movq    (%%eax), %%mm0 \n\t"	/* load 8 bytes from SrcDest into MM0 */
      "pslld   %3, %%mm0 \n\t"	/* MM0=SrcDest+C (add 8 bytes with saturation) */
      "movq    %%mm0, (%%edi) \n\t"	/* store result in SrcDest */
      "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L12023 \n\t"	/* check loop termination, proceed if required */
      "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(N)			/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterShiftLeftUint: D = ((uint)S << N) */
int SDL_imageFilterShiftLeftUint(unsigned char *Src1, unsigned char *Dest, int length, unsigned char N)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *curdest;
    unsigned int *icursrc1, *icurdest;
    int result;

    /* min. 1 bit and max. 32 bit shift is allowed */
    if ((N > 32) || (N < 1)) return (-1);

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	SDL_imageFilterShiftLeftUintMMX(Src1, Dest, length, N);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    icursrc1=(unsigned int *)cursrc1;
    icurdest=(unsigned int *)curdest;
    for (i = istart; i < length; i += 4) {
     if ((i+4)<length) {
	result = ((unsigned int)*icursrc1 << N);
	*icurdest = (unsigned int)result;
     }
     /* Advance pointers */
     icursrc1++;
     icurdest++;
    }

    return (0);
}

/*  SDL_imageFilterShiftLeftMMX: D = saturation255(S << N) */
int SDL_imageFilterShiftLeftMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned char N)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "xor       %%eax, %%eax \n\t"	/* zero EAX */
      "mov           %3, %%al \n\t"	/* load N into AL */
      "movd      %%eax, %%mm7 \n\t"	/* copy N into MM7 */
       "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 register */
       "mov         %1, %%eax  \n\t"	/* load Src1 address into eax */
      "mov         %0, %%edi  \n\t"	/* load Dest address into edi */
      "mov         %2, %%ecx  \n\t"	/* load loop counter (SIZE) into ecx */
      "shr         $3, %%ecx  \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       "cmp           $7, %%al \n\t"	/* if (N <= 7) execute more efficient code */
      "jg             .L10281 \n\t" ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L10280:               \n\t" "movq    (%%eax), %%mm3 \n\t"	/* load 8 bytes from Src1 into MM3 */
      "movq      %%mm3, %%mm4 \n\t"	/* copy MM3 into MM4  */
      "punpcklbw %%mm0, %%mm3 \n\t"	/* unpack low  bytes of SrcDest into words */
      "punpckhbw %%mm0, %%mm4 \n\t"	/* unpack high bytes of SrcDest into words */
      "psllw     %%mm7, %%mm3 \n\t"	/* shift 4 WORDS of MM3 (N) bits to the right */
      "psllw     %%mm7, %%mm4 \n\t"	/* shift 4 WORDS of MM4 (N) bits to the right */
      "packuswb  %%mm4, %%mm3 \n\t"	/* pack words back into bytes with saturation */
      "movq    %%mm3, (%%edi) \n\t"	/* store result in Dest */
       "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz            .L10280 \n\t"	/* check loop termination, proceed if required */
      "jmp            .L10282 \n\t" ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L10281:               \n\t" "movq    (%%eax), %%mm3 \n\t"	/* load 8 bytes from Src1 into MM3 */
      "movq      %%mm3, %%mm4 \n\t"	/* copy MM3 into MM4  */
      "punpcklbw %%mm0, %%mm3 \n\t"	/* unpack low  bytes of SrcDest into words */
      "punpckhbw %%mm0, %%mm4 \n\t"	/* unpack high bytes of SrcDest into words */
      "psllw     %%mm7, %%mm3 \n\t"	/* shift 4 WORDS of MM3 (N) bits to the right */
      "psllw     %%mm7, %%mm4 \n\t"	/* shift 4 WORDS of MM4 (N) bits to the right */
      /* ** Take abs value of the signed words ** */
       "movq      %%mm3, %%mm5 \n\t"	/* copy mm3 into mm5 */
      "movq      %%mm4, %%mm6 \n\t"	/* copy mm4 into mm6 */
      "psraw       $15, %%mm5 \n\t"	/* fill mm5 words with word sign bit */
      "psraw       $15, %%mm6 \n\t"	/* fill mm6 words with word sign bit */
      "pxor      %%mm5, %%mm3 \n\t"	/* take 1's compliment of only neg. words */
      "pxor      %%mm6, %%mm4 \n\t"	/* take 1's compliment of only neg. words */
      "psubsw    %%mm5, %%mm3 \n\t"	/* add 1 to only neg. words, W-(-1) or W-0 */
      "psubsw    %%mm6, %%mm4 \n\t"	/* add 1 to only neg. words, W-(-1) or W-0 */
       "packuswb  %%mm4, %%mm3 \n\t"	/* pack words back into bytes with saturation */
      "movq    %%mm3, (%%edi) \n\t"	/* store result in Dest */
       "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz            .L10281 \n\t"	/* check loop termination, proceed if required */
       ".L10282:               \n\t" "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(N)			/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterShiftLeft: D = saturation255(S << N) */
int SDL_imageFilterShiftLeft(unsigned char *Src1, unsigned char *Dest, int length, unsigned char N)
{
    unsigned int i, istart;
    unsigned char *cursrc1, *curdest;
    int result;

    if ((N > 8) || (N < 1))
	return (-1);		/* image size must be at least 8 bytes  */
    /* and min. 1 bit and max. 8 bit shift is allowed */

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	SDL_imageFilterShiftLeftMMX(Src1, Dest, length, N);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	result = (int) *cursrc1 << N;
	if (result > 255)
	    result = 255;
	*curdest = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	curdest++;
    }

    return (0);
}

/*  SDL_imageFilterBinarizeUsingThresholdMMX: D = (S >= T) ? 255:0 */
int SDL_imageFilterBinarizeUsingThresholdMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned char T)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t"
      /* ** Duplicate T in 8 bytes of MM3 ** */
      "pcmpeqb   %%mm1, %%mm1 \n\t"	/* generate all 1's in mm1 */
      "pcmpeqb   %%mm2, %%mm2 \n\t"	/* generate all 1's in mm2 */
       "mov           %3, %%al \n\t"	/* load T into AL */
      "mov         %%al, %%ah \n\t"	/* copy AL into AH */
      "mov         %%ax, %%bx \n\t"	/* copy AX into BX */
      "shl         $16, %%eax \n\t"	/* shift 2 bytes of EAX left */
      "mov         %%bx, %%ax \n\t"	/* copy BX into AX */
      "movd      %%eax, %%mm3 \n\t"	/* copy EAX into MM3 */
      "movd      %%eax, %%mm4 \n\t"	/* copy EAX into MM4 */
      "punpckldq %%mm4, %%mm3 \n\t"	/* fill higher bytes of MM3 with T */
       "psubusb   %%mm3, %%mm2 \n\t"	/* store 0xFF - T in MM2 */
       "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte alignment of the loop entry */
      ".L1029:                \n\t" 
      "movq    (%%eax), %%mm0 \n\t"	/* load 8 bytes from SrcDest into MM0 */
      "paddusb   %%mm2, %%mm0 \n\t"	/* MM0=SrcDest+(0xFF-T) (add 8 bytes with saturation) */
      "pcmpeqb   %%mm1, %%mm0 \n\t"	/* binarize 255:0, comparing to 255 */
      "movq    %%mm0, (%%edi) \n\t"	/* store result in SrcDest */
       "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L1029 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(T)			/* %3 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterBinarizeUsingThreshold: D = (S >= T) ? 255:0 */
int SDL_imageFilterBinarizeUsingThreshold(unsigned char *Src1, unsigned char *Dest, int length, unsigned char T)
{
    unsigned int i, istart;
    unsigned char *cursrc1;
    unsigned char *curdest;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	SDL_imageFilterBinarizeUsingThresholdMMX(Src1, Dest, length, T);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	*curdest = ((unsigned char) *cursrc1 >= T) ? 255 : 0;
	/* Advance pointers */
	cursrc1++;
	curdest++;
    }

    return (0);
}

/*  SDL_imageFilterClipToRangeMMX: D = (S >= Tmin) & (S <= Tmax) S:Tmin | Tmax */
int SDL_imageFilterClipToRangeMMX(unsigned char *Src1, unsigned char *Dest, int length, unsigned char Tmin,
				  unsigned char Tmax)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "pcmpeqb   %%mm1, %%mm1 \n\t"	/* generate all 1's in mm1 */
      /* ** Duplicate Tmax in 8 bytes of MM3 ** */
       "mov           %4, %%al \n\t"	/* load Tmax into AL */
      "mov         %%al, %%ah \n\t"	/* copy AL into AH */
      "mov         %%ax, %%bx \n\t"	/* copy AX into BX */
      "shl         $16, %%eax \n\t"	/* shift 2 bytes of EAX left */
      "mov         %%bx, %%ax \n\t"	/* copy BX into AX */
      "movd      %%eax, %%mm3 \n\t"	/* copy EAX into MM3 */
      "movd      %%eax, %%mm4 \n\t"	/* copy EAX into MM4 */
      "punpckldq %%mm4, %%mm3 \n\t"	/* fill higher bytes of MM3 with Tmax */
       "psubusb   %%mm3, %%mm1 \n\t"	/* store 0xFF - Tmax in MM1 */
      /* ** Duplicate Tmin in 8 bytes of MM5 ** */
       "mov           %3, %%al \n\t"	/* load Tmin into AL */
      "mov         %%al, %%ah \n\t"	/* copy AL into AH */
      "mov         %%ax, %%bx \n\t"	/* copy AX into BX */
      "shl         $16, %%eax \n\t"	/* shift 2 bytes of EAX left */
      "mov         %%bx, %%ax \n\t"	/* copy BX into AX */
      "movd      %%eax, %%mm5 \n\t"	/* copy EAX into MM5 */
      "movd      %%eax, %%mm4 \n\t"	/* copy EAX into MM4 */
      "punpckldq %%mm4, %%mm5 \n\t"	/* fill higher bytes of MM5 with Tmin */
       "movq      %%mm5, %%mm7 \n\t"	/* copy MM5 into MM7 */
      "paddusb   %%mm1, %%mm7 \n\t"	/* store 0xFF - Tmax + Tmin in MM7 */
       "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L1030:                \n\t" 
      "movq    (%%eax), %%mm0 \n\t"	/* load 8 bytes from Src1 into MM0 */
      "paddusb   %%mm1, %%mm0 \n\t"	/* MM0=SrcDest+(0xFF-Tmax) */
      "psubusb   %%mm7, %%mm0 \n\t"	/* MM0=MM0-(0xFF-Tmax+Tmin) */
      "paddusb   %%mm5, %%mm0 \n\t"	/* MM0=MM0+Tmin */
      "movq    %%mm0, (%%edi) \n\t"	/* store result in Dest */
       "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L1030 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(Tmin),		/* %3 */
      "m"(Tmax)			/* %4 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterClipToRange: D = (S >= Tmin) & (S <= Tmax) S:Tmin | Tmax */
int SDL_imageFilterClipToRange(unsigned char *Src1, unsigned char *Dest, int length, unsigned char Tmin,
			       unsigned char Tmax)
{
    unsigned int i, istart;
    unsigned char *cursrc1;
    unsigned char *curdest;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	SDL_imageFilterClipToRangeMMX(Src1, Dest, length, Tmin, Tmax);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    for (i = istart; i < length; i++) {
	if (*cursrc1 < Tmin) {
	    *curdest = Tmin;
	} else if (*cursrc1 > Tmax) {
	    *curdest = Tmax;
	} else {
	    *curdest = *cursrc1;
	}
	/* Advance pointers */
	cursrc1++;
	curdest++;
    }

    return (0);
}

/*  SDL_imageFilterNormalizeLinearMMX: D = saturation255((Nmax - Nmin)/(Cmax - Cmin)*(S - Cmin) + Nmin) */
int SDL_imageFilterNormalizeLinearMMX(unsigned char *Src1, unsigned char *Dest, int length, int Cmin, int Cmax,
				      int Nmin, int Nmax)
{
#ifdef USE_MMX
    asm volatile
     ("pusha		     \n\t" "mov           %6, %%ax \n\t"	/* load Nmax in AX */
      "mov           %4, %%bx \n\t"	/* load Cmax in BX */
      "sub           %5, %%ax \n\t"	/* AX = Nmax - Nmin */
      "sub           %3, %%bx \n\t"	/* BX = Cmax - Cmin */
      "jz             .L10311 \n\t"	/* check division by zero */
      "xor         %%dx, %%dx \n\t"	/* prepare for division, zero DX */
      "div               %%bx \n\t"	/* AX = AX/BX */
      "jmp            .L10312 \n\t" ".L10311:               \n\t" "mov         $255, %%ax \n\t"	/* if div by zero, assume result max. byte value */
       ".L10312:               \n\t"	/* ** Duplicate AX in 4 words of MM0 ** */
       "mov         %%ax, %%bx \n\t"	/* copy AX into BX */
      "shl         $16, %%eax \n\t"	/* shift 2 bytes of EAX left */
      "mov         %%bx, %%ax \n\t"	/* copy BX into AX */
      "movd      %%eax, %%mm0 \n\t"	/* copy EAX into MM0 */
      "movd      %%eax, %%mm1 \n\t"	/* copy EAX into MM1 */
      "punpckldq %%mm1, %%mm0 \n\t"	/* fill higher words of MM0 with AX */
      /* ** Duplicate Cmin in 4 words of MM1 ** */
       "mov           %3, %%ax \n\t"	/* load Cmin into AX */
      "mov         %%ax, %%bx \n\t"	/* copy AX into BX */
      "shl         $16, %%eax \n\t"	/* shift 2 bytes of EAX left */
      "mov         %%bx, %%ax \n\t"	/* copy BX into AX */
      "movd      %%eax, %%mm1 \n\t"	/* copy EAX into MM1 */
      "movd      %%eax, %%mm2 \n\t"	/* copy EAX into MM2 */
      "punpckldq %%mm2, %%mm1 \n\t"	/* fill higher words of MM1 with Cmin */
      /* ** Duplicate Nmin in 4 words of MM2 ** */
       "mov           %5, %%ax \n\t"	/* load Nmin into AX */
      "mov         %%ax, %%bx \n\t"	/* copy AX into BX */
      "shl         $16, %%eax \n\t"	/* shift 2 bytes of EAX left */
      "mov         %%bx, %%ax \n\t"	/* copy BX into AX */
      "movd      %%eax, %%mm2 \n\t"	/* copy EAX into MM2 */
      "movd      %%eax, %%mm3 \n\t"	/* copy EAX into MM3 */
      "punpckldq %%mm3, %%mm2 \n\t"	/* fill higher words of MM2 with Nmin */
       "pxor      %%mm7, %%mm7 \n\t"	/* zero MM7 register */
       "mov          %1, %%eax \n\t"	/* load Src1 address into eax */
      "mov          %0, %%edi \n\t"	/* load Dest address into edi */
      "mov          %2, %%ecx \n\t"	/* load loop counter (SIZE) into ecx */
      "shr          $3, %%ecx \n\t"	/* counter/8 (MMX loads 8 bytes at a time) */
       ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
      ".L1031:                \n\t" 
      "movq    (%%eax), %%mm3 \n\t"	/* load 8 bytes from Src1 into MM3 */
      "movq      %%mm3, %%mm4 \n\t"	/* copy MM3 into MM4  */
      "punpcklbw %%mm7, %%mm3 \n\t"	/* unpack low  bytes of SrcDest into words */
      "punpckhbw %%mm7, %%mm4 \n\t"	/* unpack high bytes of SrcDest into words */
      "psubusb   %%mm1, %%mm3 \n\t"	/* S-Cmin, low  bytes */
      "psubusb   %%mm1, %%mm4 \n\t"	/* S-Cmin, high bytes */
      "pmullw    %%mm0, %%mm3 \n\t"	/* MM0*(S-Cmin), low  bytes */
      "pmullw    %%mm0, %%mm4 \n\t"	/* MM0*(S-Cmin), high bytes */
      "paddusb   %%mm2, %%mm3 \n\t"	/* MM0*(S-Cmin)+Nmin, low  bytes */
      "paddusb   %%mm2, %%mm4 \n\t"	/* MM0*(S-Cmin)+Nmin, high bytes */
      /* ** Take abs value of the signed words ** */
       "movq      %%mm3, %%mm5 \n\t"	/* copy mm3 into mm5 */
      "movq      %%mm4, %%mm6 \n\t"	/* copy mm4 into mm6 */
      "psraw       $15, %%mm5 \n\t"	/* fill mm5 words with word sign bit */
      "psraw       $15, %%mm6 \n\t"	/* fill mm6 words with word sign bit */
      "pxor      %%mm5, %%mm3 \n\t"	/* take 1's compliment of only neg. words */
      "pxor      %%mm6, %%mm4 \n\t"	/* take 1's compliment of only neg. words */
      "psubsw    %%mm5, %%mm3 \n\t"	/* add 1 to only neg. words, W-(-1) or W-0 */
      "psubsw    %%mm6, %%mm4 \n\t"	/* add 1 to only neg. words, W-(-1) or W-0 */
      "packuswb  %%mm4, %%mm3 \n\t"	/* pack words back into bytes with saturation */
       "movq    %%mm3, (%%edi) \n\t"	/* store result in Dest */
       "add          $8, %%eax \n\t"	/* increase Src1 register pointer by 8 */
      "add          $8, %%edi \n\t"	/* increase Dest register pointer by 8 */
      "dec              %%ecx \n\t"	/* decrease loop counter */
      "jnz             .L1031 \n\t"	/* check loop termination, proceed if required */
       "emms                   \n\t"	/* exit MMX state */
      "popa                   \n\t":"=m" (Dest)	/* %0 */
      :"m"(Src1),		/* %1 */
      "m"(length),		/* %2 */
      "m"(Cmin),		/* %3 */
      "m"(Cmax),		/* %4 */
      "m"(Nmin),		/* %5 */
      "m"(Nmax)			/* %6 */
	);
#endif
    return (0);
}

/*  SDL_imageFilterNormalizeLinear: D = saturation255((Nmax - Nmin)/(Cmax - Cmin)*(S - Cmin) + Nmin) */
int SDL_imageFilterNormalizeLinear(unsigned char *Src1, unsigned char *Dest, int length, int Cmin, int Cmax, int Nmin,
				   int Nmax)
{
    unsigned int i, istart;
    unsigned char *cursrc1;
    unsigned char *curdest;
    int dN, dC, factor;
    int result;

    if ((SDL_imageFilterMMXdetect()) && (length > 7)) {

	SDL_imageFilterNormalizeLinearMMX(Src1, Dest, length, Cmin, Cmax, Nmin, Nmax);

	/* Check for unaligned bytes */
	if ((length & 7) > 0) {
	    /* Setup to process unaligned bytes */
	    istart = length & 0xfffffff8;
	    cursrc1 = &Src1[istart];
	    curdest = &Dest[istart];
	} else {
	    /* No unaligned bytes - we are done */
	    return (0);
	}
    } else {
	/* Setup to process whole image */
	istart = 0;
	cursrc1 = Src1;
	curdest = Dest;
    }

    /* C routine to process image */
    dC = Cmax - Cmin;
    if (dC == 0)
	return (0);
    dN = Nmax - Nmin;
    factor = dN / dC;
    for (i = istart; i < length; i++) {
	result = factor * ((int) (*cursrc1) - Cmin) + Nmin;
	if (result > 255)
	    result = 255;
	*curdest = (unsigned char) result;
	/* Advance pointers */
	cursrc1++;
	curdest++;
    }

    return (0);
}

/* ------------------------------------------------------------------------------------ */

/*  SDL_imageFilterConvolveKernel3x3Divide: Dij = saturation0and255( ... ) */
int SDL_imageFilterConvolveKernel3x3Divide(unsigned char *Src, unsigned char *Dest, int rows, int columns,
					   signed short *Kernel, unsigned char Divisor)
{
    if ((columns < 3) || (rows < 3) || (Divisor == 0))
	return (-1);

    if ((SDL_imageFilterMMXdetect())) {
#ifdef USE_MMX
	asm volatile
	 ("pusha		     \n\t" "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 */
	  "xor       %%ebx, %%ebx \n\t"	/* zero EBX */
	  "mov           %5, %%bl \n\t"	/* load Divisor into BL */
	   "mov          %4, %%edx \n\t"	/* load Kernel address into EDX */
	  "movq    (%%edx), %%mm5 \n\t"	/* MM5 = {0,K2,K1,K0} */
	  "add          $8, %%edx \n\t"	/* second row              |K0 K1 K2 0| */
	  "movq    (%%edx), %%mm6 \n\t"	/* MM6 = {0,K5,K4,K3}  K = |K3 K4 K5 0| */
	  "add          $8, %%edx \n\t"	/* third row               |K6 K7 K8 0| */
	  "movq    (%%edx), %%mm7 \n\t"	/* MM7 = {0,K8,K7,K6} */
/* --- */
	  "mov          %3, %%eax \n\t"	/* load columns into EAX */
	  "mov          %1, %%esi \n\t"	/* ESI = Src row 0 address */
	  "mov          %0, %%edi \n\t"	/* load Dest address to EDI */
	  "add       %%eax, %%edi \n\t"	/* EDI = EDI + columns */
	  "inc              %%edi \n\t"	/* 1 byte offset from the left edge */
	   "mov          %2, %%edx \n\t"	/* initialize ROWS counter */
	  "sub          $2, %%edx \n\t"	/* do not use first and last row */
/* --- */
	  ".L10320:               \n\t" "mov       %%eax, %%ecx \n\t"	/* initialize COLUMS counter */
	  "sub          $2, %%ecx \n\t"	/* do not use first and last column */
	   ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
	  ".L10322:               \n\t"
/* --- */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the image first row */
	  "add       %%eax, %%esi \n\t"	/* move one row below */
	  "movq    (%%esi), %%mm2 \n\t"	/* load 8 bytes of the image second row */
	  "add       %%eax, %%esi \n\t"	/* move one row below */
	  "movq    (%%esi), %%mm3 \n\t"	/* load 8 bytes of the image third row */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first 4 bytes into words */
	  "punpcklbw %%mm0, %%mm2 \n\t"	/* unpack first 4 bytes into words */
	  "punpcklbw %%mm0, %%mm3 \n\t"	/* unpack first 4 bytes into words */
	   "pmullw    %%mm5, %%mm1 \n\t"	/* multiply words first row  image*Kernel */
	  "pmullw    %%mm6, %%mm2 \n\t"	/* multiply words second row image*Kernel */
	  "pmullw    %%mm7, %%mm3 \n\t"	/* multiply words third row  image*Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the first and second rows */
	  "paddsw    %%mm3, %%mm1 \n\t"	/* add 4 words of the third row and result */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "psrlq       $32, %%mm1 \n\t"	/* shift 2 left words to the right */
	  "paddsw    %%mm2, %%mm1 \n\t"	/* add 2 left and 2 right result words */
	  "movq      %%mm1, %%mm3 \n\t"	/* copy MM1 into MM3 */
	  "psrlq       $16, %%mm1 \n\t"	/* shift 1 left word to the right */
	  "paddsw    %%mm3, %%mm1 \n\t"	/* add 1 left and 1 right result words */
/* -- */
	  "movd      %%eax, %%mm2 \n\t"	/* save EAX in MM2 */
	  "movd      %%edx, %%mm3 \n\t"	/* save EDX in MM3 */
	  "movd      %%mm1, %%eax \n\t"	/* copy MM1 into EAX */
	  "psraw       $15, %%mm1 \n\t"	/* spread sign bit of the result */
	  "movd      %%mm1, %%edx \n\t"	/* fill EDX with a sign bit */
	  "idivw             %%bx \n\t"	/* IDIV - VERY EXPENSIVE */
	  "movd      %%eax, %%mm1 \n\t"	/* move result of division into MM1 */
	  "packuswb  %%mm0, %%mm1 \n\t"	/* pack division result with saturation */
	  "movd      %%mm1, %%eax \n\t"	/* copy saturated result into EAX */
	  "mov      %%al, (%%edi) \n\t"	/* copy a byte result into Dest */
	  "movd      %%mm3, %%edx \n\t"	/* restore saved EDX */
	  "movd      %%mm2, %%eax \n\t"	/* restore saved EAX */
/* -- */
	  "sub       %%eax, %%esi \n\t"	/* move two rows up */
	  "sub       %%eax, %%esi \n\t"	/* */
	  "inc              %%esi \n\t"	/* move Src  pointer to the next pixel */
	  "inc              %%edi \n\t"	/* move Dest pointer to the next pixel */
/* --- */
	  "dec              %%ecx \n\t"	/* decrease loop counter COLUMNS */
	  "jnz            .L10322 \n\t"	/* check loop termination, proceed if required */
	   "add          $2, %%esi \n\t"	/* move to the next row in Src */
	  "add          $2, %%edi \n\t"	/* move to the next row in Dest */
	   "dec              %%edx \n\t"	/* decrease loop counter ROWS */
	  "jnz            .L10320 \n\t"	/* check loop termination, proceed if required */
/* --- */
	  "emms                   \n\t"	/* exit MMX state */
	  "popa                   \n\t":"=m" (Dest)	/* %0 */
	  :"m"(Src),		/* %1 */
	  "m"(rows),		/* %2 */
	  "m"(columns),		/* %3 */
	  "m"(Kernel),		/* %4 */
	  "m"(Divisor)		/* %5 */
	    );
#endif
	return (0);
    } else {
	/* No non-MMX implementation yet */
	return (-1);
    }
}

/*  SDL_imageFilterConvolveKernel5x5Divide: Dij = saturation0and255( ... ) */
int SDL_imageFilterConvolveKernel5x5Divide(unsigned char *Src, unsigned char *Dest, int rows, int columns,
					   signed short *Kernel, unsigned char Divisor)
{
    if ((columns < 5) || (rows < 5) || (Divisor == 0))
	return (-1);

    if ((SDL_imageFilterMMXdetect())) {
#ifdef USE_MMX
	asm volatile
	 ("pusha		     \n\t" "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 */
	   "xor       %%ebx, %%ebx \n\t"	/* zero EBX */
	  "mov           %5, %%bl \n\t"	/* load Divisor into BL */
	  "movd      %%ebx, %%mm5 \n\t"	/* copy Divisor into MM5 */
	   "mov          %4, %%edx \n\t"	/* load Kernel address into EDX */
	  "mov          %1, %%esi \n\t"	/* load Src  address to ESI */
	  "mov          %0, %%edi \n\t"	/* load Dest address to EDI */
	  "add          $2, %%edi \n\t"	/* 2 column offset from the left edge */
	  "mov          %3, %%eax \n\t"	/* load columns into EAX */
	  "shl          $1, %%eax \n\t"	/* EAX = columns * 2 */
	  "add       %%eax, %%edi \n\t"	/* 2 row offset from the top edge */
	  "shr          $1, %%eax \n\t"	/* EAX = columns */
	   "mov          %2, %%ebx \n\t"	/* initialize ROWS counter */
	  "sub          $4, %%ebx \n\t"	/* do not use first 2 and last 2 rows */
/* --- */
	  ".L10330:               \n\t" "mov       %%eax, %%ecx \n\t"	/* initialize COLUMNS counter */
	  "sub          $4, %%ecx \n\t"	/* do not use first 2 and last 2 columns */
	   ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
	  ".L10332:               \n\t" "pxor      %%mm7, %%mm7 \n\t"	/* zero MM7 (accumulator) */
	  "movd      %%esi, %%mm6 \n\t"	/* save ESI in MM6 */
/* --- 1 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 2 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 3 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 4 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 5 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- */
	  "movq      %%mm7, %%mm3 \n\t"	/* copy MM7 into MM3 */
	  "psrlq       $32, %%mm7 \n\t"	/* shift 2 left words to the right */
	  "paddsw    %%mm3, %%mm7 \n\t"	/* add 2 left and 2 right result words */
	  "movq      %%mm7, %%mm2 \n\t"	/* copy MM7 into MM2 */
	  "psrlq       $16, %%mm7 \n\t"	/* shift 1 left word to the right */
	  "paddsw    %%mm2, %%mm7 \n\t"	/* add 1 left and 1 right result words */
/* --- */
	  "movd      %%eax, %%mm1 \n\t"	/* save EDX in MM1 */
	  "movd      %%ebx, %%mm2 \n\t"	/* save EDX in MM2 */
	  "movd      %%edx, %%mm3 \n\t"	/* save EDX in MM3 */
	   "movd      %%mm7, %%eax \n\t"	/* load summation result into EAX */
	  "psraw       $15, %%mm7 \n\t"	/* spread sign bit of the result */
	  "movd      %%mm5, %%ebx \n\t"	/* load Divisor into EBX */
	  "movd      %%mm7, %%edx \n\t"	/* fill EDX with a sign bit */
	  "idivw             %%bx \n\t"	/* IDIV - VERY EXPENSIVE */
	  "movd      %%eax, %%mm7 \n\t"	/* move result of division into MM7 */
	  "packuswb  %%mm0, %%mm7 \n\t"	/* pack division result with saturation */
	   "movd      %%mm7, %%eax \n\t"	/* copy saturated result into EAX */
	  "mov      %%al, (%%edi) \n\t"	/* copy a byte result into Dest */
	   "movd      %%mm3, %%edx \n\t"	/* restore saved EDX */
	  "movd      %%mm2, %%ebx \n\t"	/* restore saved EBX */
	  "movd      %%mm1, %%eax \n\t"	/* restore saved EAX */
/* -- */
	  "movd      %%mm6, %%esi \n\t"	/* move Src pointer to the top pixel */
	  "sub         $72, %%edx \n\t"	/* EDX = Kernel address */
	  "inc              %%esi \n\t"	/* move Src  pointer to the next pixel */
	  "inc              %%edi \n\t"	/* move Dest pointer to the next pixel */
/* --- */
	  "dec              %%ecx \n\t"	/* decrease loop counter COLUMNS */
	  "jnz            .L10332 \n\t"	/* check loop termination, proceed if required */
	   "add          $4, %%esi \n\t"	/* move to the next row in Src */
	  "add          $4, %%edi \n\t"	/* move to the next row in Dest */
	   "dec              %%ebx \n\t"	/* decrease loop counter ROWS */
	  "jnz            .L10330 \n\t"	/* check loop termination, proceed if required */
/* --- */
	  "emms                   \n\t"	/* exit MMX state */
	  "popa                   \n\t":"=m" (Dest)	/* %0 */
	  :"m"(Src),		/* %1 */
	  "m"(rows),		/* %2 */
	  "m"(columns),		/* %3 */
	  "m"(Kernel),		/* %4 */
	  "m"(Divisor)		/* %5 */
	    );
#endif
	return (0);
    } else {
	/* No non-MMX implementation yet */
	return (-1);
    }
}

/*  SDL_imageFilterConvolveKernel7x7Divide: Dij = saturation0and255( ... ) */
int SDL_imageFilterConvolveKernel7x7Divide(unsigned char *Src, unsigned char *Dest, int rows, int columns,
					   signed short *Kernel, unsigned char Divisor)
{
    if ((columns < 7) || (rows < 7) || (Divisor == 0))
	return (-1);

    if ((SDL_imageFilterMMXdetect())) {
#ifdef USE_MMX
	asm volatile
	 ("pusha		     \n\t" "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 */
	   "xor       %%ebx, %%ebx \n\t"	/* zero EBX */
	  "mov           %5, %%bl \n\t"	/* load Divisor into BL */
	  "movd      %%ebx, %%mm5 \n\t"	/* copy Divisor into MM5 */
	   "mov          %4, %%edx \n\t"	/* load Kernel address into EDX */
	  "mov          %1, %%esi \n\t"	/* load Src  address to ESI */
	  "mov          %0, %%edi \n\t"	/* load Dest address to EDI */
	  "add          $3, %%edi \n\t"	/* 3 column offset from the left edge */
	  "mov          %3, %%eax \n\t"	/* load columns into EAX */
	  "add       %%eax, %%edi \n\t"	/* 3 row offset from the top edge */
	  "add       %%eax, %%edi \n\t" "add       %%eax, %%edi \n\t" "mov          %2, %%ebx \n\t"	/* initialize ROWS counter */
	  "sub          $6, %%ebx \n\t"	/* do not use first 3 and last 3 rows */
/* --- */
	  ".L10340:               \n\t" "mov       %%eax, %%ecx \n\t"	/* initialize COLUMNS counter */
	  "sub          $6, %%ecx \n\t"	/* do not use first 3 and last 3 columns */
	   ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
	  ".L10342:               \n\t" "pxor      %%mm7, %%mm7 \n\t"	/* zero MM7 (accumulator) */
	  "movd      %%esi, %%mm6 \n\t"	/* save ESI in MM6 */
/* --- 1 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 2 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 3 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 4 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 5 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 6 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 7 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- */
	  "movq      %%mm7, %%mm3 \n\t"	/* copy MM7 into MM3 */
	  "psrlq       $32, %%mm7 \n\t"	/* shift 2 left words to the right */
	  "paddsw    %%mm3, %%mm7 \n\t"	/* add 2 left and 2 right result words */
	  "movq      %%mm7, %%mm2 \n\t"	/* copy MM7 into MM2 */
	  "psrlq       $16, %%mm7 \n\t"	/* shift 1 left word to the right */
	  "paddsw    %%mm2, %%mm7 \n\t"	/* add 1 left and 1 right result words */
/* --- */
	  "movd      %%eax, %%mm1 \n\t"	/* save EDX in MM1 */
	  "movd      %%ebx, %%mm2 \n\t"	/* save EDX in MM2 */
	  "movd      %%edx, %%mm3 \n\t"	/* save EDX in MM3 */
	   "movd      %%mm7, %%eax \n\t"	/* load summation result into EAX */
	  "psraw       $15, %%mm7 \n\t"	/* spread sign bit of the result */
	  "movd      %%mm5, %%ebx \n\t"	/* load Divisor into EBX */
	  "movd      %%mm7, %%edx \n\t"	/* fill EDX with a sign bit */
	  "idivw             %%bx \n\t"	/* IDIV - VERY EXPENSIVE */
	  "movd      %%eax, %%mm7 \n\t"	/* move result of division into MM7 */
	  "packuswb  %%mm0, %%mm7 \n\t"	/* pack division result with saturation */
	   "movd      %%mm7, %%eax \n\t"	/* copy saturated result into EAX */
	  "mov      %%al, (%%edi) \n\t"	/* copy a byte result into Dest */
	   "movd      %%mm3, %%edx \n\t"	/* restore saved EDX */
	  "movd      %%mm2, %%ebx \n\t"	/* restore saved EBX */
	  "movd      %%mm1, %%eax \n\t"	/* restore saved EAX */
/* -- */
	  "movd      %%mm6, %%esi \n\t"	/* move Src pointer to the top pixel */
	  "sub        $104, %%edx \n\t"	/* EDX = Kernel address */
	  "inc              %%esi \n\t"	/* move Src  pointer to the next pixel */
	  "inc              %%edi \n\t"	/* move Dest pointer to the next pixel */
/* --- */
	  "dec              %%ecx \n\t"	/* decrease loop counter COLUMNS */
	  "jnz            .L10342 \n\t"	/* check loop termination, proceed if required */
	   "add          $6, %%esi \n\t"	/* move to the next row in Src */
	  "add          $6, %%edi \n\t"	/* move to the next row in Dest */
	   "dec              %%ebx \n\t"	/* decrease loop counter ROWS */
	  "jnz            .L10340 \n\t"	/* check loop termination, proceed if required */
/* --- */
	  "emms                   \n\t"	/* exit MMX state */
	  "popa                   \n\t":"=m" (Dest)	/* %0 */
	  :"m"(Src),		/* %1 */
	  "m"(rows),		/* %2 */
	  "m"(columns),		/* %3 */
	  "m"(Kernel),		/* %4 */
	  "m"(Divisor)		/* %5 */
	    );
#endif
	return (0);
    } else {
	/* No non-MMX implementation yet */
	return (-1);
    }
}

/*  SDL_imageFilterConvolveKernel9x9Divide: Dij = saturation0and255( ... ) */
int SDL_imageFilterConvolveKernel9x9Divide(unsigned char *Src, unsigned char *Dest, int rows, int columns,
					   signed short *Kernel, unsigned char Divisor)
{
    if ((columns < 9) || (rows < 9) || (Divisor == 0))
	return (-1);

    if ((SDL_imageFilterMMXdetect())) {
#ifdef USE_MMX
	asm volatile
	 ("pusha		     \n\t" "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 */
	   "xor       %%ebx, %%ebx \n\t"	/* zero EBX */
	  "mov           %5, %%bl \n\t"	/* load Divisor into BL */
	  "movd      %%ebx, %%mm5 \n\t"	/* copy Divisor into MM5 */
	   "mov          %4, %%edx \n\t"	/* load Kernel address into EDX */
	  "mov          %1, %%esi \n\t"	/* load Src  address to ESI */
	  "mov          %0, %%edi \n\t"	/* load Dest address to EDI */
	  "add          $4, %%edi \n\t"	/* 4 column offset from the left edge */
	  "mov          %3, %%eax \n\t"	/* load columns into EAX */
	  "add       %%eax, %%edi \n\t"	/* 4 row offset from the top edge */
	  "add       %%eax, %%edi \n\t" "add       %%eax, %%edi \n\t" "add       %%eax, %%edi \n\t" "mov          %2, %%ebx \n\t"	/* initialize ROWS counter */
	  "sub          $8, %%ebx \n\t"	/* do not use first 4 and last 4 rows */
/* --- */
	  ".L10350:               \n\t" "mov       %%eax, %%ecx \n\t"	/* initialize COLUMNS counter */
	  "sub          $8, %%ecx \n\t"	/* do not use first 4 and last 4 columns */
	   ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
	  ".L10352:               \n\t" "pxor      %%mm7, %%mm7 \n\t"	/* zero MM7 (accumulator) */
	  "movd      %%esi, %%mm6 \n\t"	/* save ESI in MM6 */
/* --- 1 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 2 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 3 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 4 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 5 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 6 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 7 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 8 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 9 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- */
	  "movq      %%mm7, %%mm3 \n\t"	/* copy MM7 into MM3 */
	  "psrlq       $32, %%mm7 \n\t"	/* shift 2 left words to the right */
	  "paddsw    %%mm3, %%mm7 \n\t"	/* add 2 left and 2 right result words */
	  "movq      %%mm7, %%mm2 \n\t"	/* copy MM7 into MM2 */
	  "psrlq       $16, %%mm7 \n\t"	/* shift 1 left word to the right */
	  "paddsw    %%mm2, %%mm7 \n\t"	/* add 1 left and 1 right result words */
/* --- */
	  "movd      %%eax, %%mm1 \n\t"	/* save EDX in MM1 */
	  "movd      %%ebx, %%mm2 \n\t"	/* save EDX in MM2 */
	  "movd      %%edx, %%mm3 \n\t"	/* save EDX in MM3 */
	   "movd      %%mm7, %%eax \n\t"	/* load summation result into EAX */
	  "psraw       $15, %%mm7 \n\t"	/* spread sign bit of the result */
	  "movd      %%mm5, %%ebx \n\t"	/* load Divisor into EBX */
	  "movd      %%mm7, %%edx \n\t"	/* fill EDX with a sign bit */
	  "idivw             %%bx \n\t"	/* IDIV - VERY EXPENSIVE */
	  "movd      %%eax, %%mm7 \n\t"	/* move result of division into MM7 */
	  "packuswb  %%mm0, %%mm7 \n\t"	/* pack division result with saturation */
	   "movd      %%mm7, %%eax \n\t"	/* copy saturated result into EAX */
	  "mov      %%al, (%%edi) \n\t"	/* copy a byte result into Dest */
	   "movd      %%mm3, %%edx \n\t"	/* restore saved EDX */
	  "movd      %%mm2, %%ebx \n\t"	/* restore saved EBX */
	  "movd      %%mm1, %%eax \n\t"	/* restore saved EAX */
/* -- */
	  "movd      %%mm6, %%esi \n\t"	/* move Src pointer to the top pixel */
	  "sub        $208, %%edx \n\t"	/* EDX = Kernel address */
	  "inc              %%esi \n\t"	/* move Src  pointer to the next pixel */
	  "inc              %%edi \n\t"	/* move Dest pointer to the next pixel */
/* --- */
	  "dec              %%ecx \n\t"	/* decrease loop counter COLUMNS */
	  "jnz            .L10352 \n\t"	/* check loop termination, proceed if required */
	   "add          $8, %%esi \n\t"	/* move to the next row in Src */
	  "add          $8, %%edi \n\t"	/* move to the next row in Dest */
	   "dec              %%ebx \n\t"	/* decrease loop counter ROWS */
	  "jnz            .L10350 \n\t"	/* check loop termination, proceed if required */
/* --- */
	  "emms                   \n\t"	/* exit MMX state */
	  "popa                   \n\t":"=m" (Dest)	/* %0 */
	  :"m"(Src),		/* %1 */
	  "m"(rows),		/* %2 */
	  "m"(columns),		/* %3 */
	  "m"(Kernel),		/* %4 */
	  "m"(Divisor)		/* %5 */
	    );
#endif
	return (0);
    } else {
	/* No non-MMX implementation yet */
	return (-1);
    }
}

/*  SDL_imageFilterConvolveKernel3x3ShiftRight: Dij = saturation0and255( ... ) */
int SDL_imageFilterConvolveKernel3x3ShiftRight(unsigned char *Src, unsigned char *Dest, int rows, int columns,
					       signed short *Kernel, unsigned char NRightShift)
{
    if ((columns < 3) || (rows < 3) || (NRightShift > 7))
	return (-1);

    if ((SDL_imageFilterMMXdetect())) {
#ifdef USE_MMX
	asm volatile
	 ("pusha		     \n\t" "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 */
	   "xor       %%ebx, %%ebx \n\t"	/* zero EBX */
	  "mov           %5, %%bl \n\t"	/* load NRightShift into BL */
	  "movd      %%ebx, %%mm4 \n\t"	/* copy NRightShift into MM4 */
	   "mov          %4, %%edx \n\t"	/* load Kernel address into EDX */
	  "movq    (%%edx), %%mm5 \n\t"	/* MM5 = {0,K2,K1,K0} */
	  "add          $8, %%edx \n\t"	/* second row              |K0 K1 K2 0| */
	  "movq    (%%edx), %%mm6 \n\t"	/* MM6 = {0,K5,K4,K3}  K = |K3 K4 K5 0| */
	  "add          $8, %%edx \n\t"	/* third row               |K6 K7 K8 0| */
	  "movq    (%%edx), %%mm7 \n\t"	/* MM7 = {0,K8,K7,K6} */
/* --- */
	  "mov          %3, %%eax \n\t"	/* load columns into EAX */
	  "mov          %1, %%esi \n\t"	/* ESI = Src row 0 address */
	  "mov          %0, %%edi \n\t"	/* load Dest address to EDI */
	  "add       %%eax, %%edi \n\t"	/* EDI = EDI + columns */
	  "inc              %%edi \n\t"	/* 1 byte offset from the left edge */
	   "mov          %2, %%edx \n\t"	/* initialize ROWS counter */
	  "sub          $2, %%edx \n\t"	/* do not use first and last row */
/* --- */
	  ".L10360:               \n\t" "mov       %%eax, %%ecx \n\t"	/* initialize COLUMS counter */
	  "sub          $2, %%ecx \n\t"	/* do not use first and last column */
	   ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
	  ".L10362:               \n\t"
/* --- */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the image first row */
	  "add       %%eax, %%esi \n\t"	/* move one row below */
	  "movq    (%%esi), %%mm2 \n\t"	/* load 8 bytes of the image second row */
	  "add       %%eax, %%esi \n\t"	/* move one row below */
	  "movq    (%%esi), %%mm3 \n\t"	/* load 8 bytes of the image third row */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first 4 bytes into words */
	  "punpcklbw %%mm0, %%mm2 \n\t"	/* unpack first 4 bytes into words */
	  "punpcklbw %%mm0, %%mm3 \n\t"	/* unpack first 4 bytes into words */
	   "psrlw     %%mm4, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm4, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm4, %%mm3 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm5, %%mm1 \n\t"	/* multiply words first row  image*Kernel */
	  "pmullw    %%mm6, %%mm2 \n\t"	/* multiply words second row image*Kernel */
	  "pmullw    %%mm7, %%mm3 \n\t"	/* multiply words third row  image*Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the first and second rows */
	  "paddsw    %%mm3, %%mm1 \n\t"	/* add 4 words of the third row and result */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "psrlq       $32, %%mm1 \n\t"	/* shift 2 left words to the right */
	  "paddsw    %%mm2, %%mm1 \n\t"	/* add 2 left and 2 right result words */
	  "movq      %%mm1, %%mm3 \n\t"	/* copy MM1 into MM3 */
	  "psrlq       $16, %%mm1 \n\t"	/* shift 1 left word to the right */
	  "paddsw    %%mm3, %%mm1 \n\t"	/* add 1 left and 1 right result words */
	  "packuswb  %%mm0, %%mm1 \n\t"	/* pack shift result with saturation */
	  "movd      %%mm1, %%ebx \n\t"	/* copy saturated result into EBX */
	  "mov      %%bl, (%%edi) \n\t"	/* copy a byte result into Dest */
/* -- */
	  "sub       %%eax, %%esi \n\t"	/* move two rows up */
	  "sub       %%eax, %%esi \n\t" "inc              %%esi \n\t"	/* move Src  pointer to the next pixel */
	  "inc              %%edi \n\t"	/* move Dest pointer to the next pixel */
/* --- */
	  "dec              %%ecx \n\t"	/* decrease loop counter COLUMNS */
	  "jnz            .L10362 \n\t"	/* check loop termination, proceed if required */
	   "add          $2, %%esi \n\t"	/* move to the next row in Src */
	  "add          $2, %%edi \n\t"	/* move to the next row in Dest */
	   "dec              %%edx \n\t"	/* decrease loop counter ROWS */
	  "jnz            .L10360 \n\t"	/* check loop termination, proceed if required */
/* --- */
	  "emms                   \n\t"	/* exit MMX state */
	  "popa                   \n\t":"=m" (Dest)	/* %0 */
	  :"m"(Src),		/* %1 */
	  "m"(rows),		/* %2 */
	  "m"(columns),		/* %3 */
	  "m"(Kernel),		/* %4 */
	  "m"(NRightShift)	/* %5 */
	    );
#endif
	return (0);
    } else {
	/* No non-MMX implementation yet */
	return (-1);
    }
}

/*  SDL_imageFilterConvolveKernel5x5ShiftRight: Dij = saturation0and255( ... ) */
int SDL_imageFilterConvolveKernel5x5ShiftRight(unsigned char *Src, unsigned char *Dest, int rows, int columns,
					       signed short *Kernel, unsigned char NRightShift)
{
    if ((columns < 5) || (rows < 5) || (NRightShift > 7))
	return (-1);

    if ((SDL_imageFilterMMXdetect())) {
#ifdef USE_MMX
	asm volatile
	 ("pusha		     \n\t" "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 */
	   "xor       %%ebx, %%ebx \n\t"	/* zero EBX */
	  "mov           %5, %%bl \n\t"	/* load NRightShift into BL */
	  "movd      %%ebx, %%mm5 \n\t"	/* copy NRightShift into MM5 */
	   "mov          %4, %%edx \n\t"	/* load Kernel address into EDX */
	  "mov          %1, %%esi \n\t"	/* load Src  address to ESI */
	  "mov          %0, %%edi \n\t"	/* load Dest address to EDI */
	  "add          $2, %%edi \n\t"	/* 2 column offset from the left edge */
	  "mov          %3, %%eax \n\t"	/* load columns into EAX */
	  "shl          $1, %%eax \n\t"	/* EAX = columns * 2 */
	  "add       %%eax, %%edi \n\t"	/* 2 row offset from the top edge */
	  "shr          $1, %%eax \n\t"	/* EAX = columns */
	   "mov          %2, %%ebx \n\t"	/* initialize ROWS counter */
	  "sub          $4, %%ebx \n\t"	/* do not use first 2 and last 2 rows */
/* --- */
	  ".L10370:               \n\t" "mov       %%eax, %%ecx \n\t"	/* initialize COLUMNS counter */
	  "sub          $4, %%ecx \n\t"	/* do not use first 2 and last 2 columns */
	   ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
	  ".L10372:               \n\t" "pxor      %%mm7, %%mm7 \n\t"	/* zero MM7 (accumulator) */
	  "movd      %%esi, %%mm6 \n\t"	/* save ESI in MM6 */
/* --- 1 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 2 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 3 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 4 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 5 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- */
	  "movq      %%mm7, %%mm3 \n\t"	/* copy MM7 into MM3 */
	  "psrlq       $32, %%mm7 \n\t"	/* shift 2 left words to the right */
	  "paddsw    %%mm3, %%mm7 \n\t"	/* add 2 left and 2 right result words */
	  "movq      %%mm7, %%mm2 \n\t"	/* copy MM7 into MM2 */
	  "psrlq       $16, %%mm7 \n\t"	/* shift 1 left word to the right */
	  "paddsw    %%mm2, %%mm7 \n\t"	/* add 1 left and 1 right result words */
	  "movd      %%eax, %%mm1 \n\t"	/* save EAX in MM1 */
	  "packuswb  %%mm0, %%mm7 \n\t"	/* pack division result with saturation */
	  "movd      %%mm7, %%eax \n\t"	/* copy saturated result into EAX */
	  "mov      %%al, (%%edi) \n\t"	/* copy a byte result into Dest */
	  "movd      %%mm1, %%eax \n\t"	/* restore saved EAX */
/* -- */
	  "movd      %%mm6, %%esi \n\t"	/* move Src pointer to the top pixel */
	  "sub         $72, %%edx \n\t"	/* EDX = Kernel address */
	  "inc              %%esi \n\t"	/* move Src  pointer to the next pixel */
	  "inc              %%edi \n\t"	/* move Dest pointer to the next pixel */
/* --- */
	  "dec              %%ecx \n\t"	/* decrease loop counter COLUMNS */
	  "jnz            .L10372 \n\t"	/* check loop termination, proceed if required */
	   "add          $4, %%esi \n\t"	/* move to the next row in Src */
	  "add          $4, %%edi \n\t"	/* move to the next row in Dest */
	   "dec              %%ebx \n\t"	/* decrease loop counter ROWS */
	  "jnz            .L10370 \n\t"	/* check loop termination, proceed if required */
/* --- */
	  "emms                   \n\t"	/* exit MMX state */
	  "popa                   \n\t":"=m" (Dest)	/* %0 */
	  :"m"(Src),		/* %1 */
	  "m"(rows),		/* %2 */
	  "m"(columns),		/* %3 */
	  "m"(Kernel),		/* %4 */
	  "m"(NRightShift)	/* %5 */
	    );
#endif
	return (0);
    } else {
	/* No non-MMX implementation yet */
	return (-1);
    }
}

/*  SDL_imageFilterConvolveKernel7x7ShiftRight: Dij = saturation0and255( ... ) */
int SDL_imageFilterConvolveKernel7x7ShiftRight(unsigned char *Src, unsigned char *Dest, int rows, int columns,
					       signed short *Kernel, unsigned char NRightShift)
{
    if ((columns < 7) || (rows < 7) || (NRightShift > 7))
	return (-1);

    if ((SDL_imageFilterMMXdetect())) {
#ifdef USE_MMX
	asm volatile
	 ("pusha		     \n\t" "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 */
	   "xor       %%ebx, %%ebx \n\t"	/* zero EBX */
	  "mov           %5, %%bl \n\t"	/* load NRightShift into BL */
	  "movd      %%ebx, %%mm5 \n\t"	/* copy NRightShift into MM5 */
	   "mov          %4, %%edx \n\t"	/* load Kernel address into EDX */
	  "mov          %1, %%esi \n\t"	/* load Src  address to ESI */
	  "mov          %0, %%edi \n\t"	/* load Dest address to EDI */
	  "add          $3, %%edi \n\t"	/* 3 column offset from the left edge */
	  "mov          %3, %%eax \n\t"	/* load columns into EAX */
	  "add       %%eax, %%edi \n\t"	/* 3 row offset from the top edge */
	  "add       %%eax, %%edi \n\t" "add       %%eax, %%edi \n\t" "mov          %2, %%ebx \n\t"	/* initialize ROWS counter */
	  "sub          $6, %%ebx \n\t"	/* do not use first 3 and last 3 rows */
/* --- */
	  ".L10380:               \n\t" "mov       %%eax, %%ecx \n\t"	/* initialize COLUMNS counter */
	  "sub          $6, %%ecx \n\t"	/* do not use first 3 and last 3 columns */
	   ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
	  ".L10382:               \n\t" "pxor      %%mm7, %%mm7 \n\t"	/* zero MM7 (accumulator) */
	  "movd      %%esi, %%mm6 \n\t"	/* save ESI in MM6 */
/* --- 1 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 2 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 3 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 4 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 5 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 6 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 7 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- */
	  "movq      %%mm7, %%mm3 \n\t"	/* copy MM7 into MM3 */
	  "psrlq       $32, %%mm7 \n\t"	/* shift 2 left words to the right */
	  "paddsw    %%mm3, %%mm7 \n\t"	/* add 2 left and 2 right result words */
	  "movq      %%mm7, %%mm2 \n\t"	/* copy MM7 into MM2 */
	  "psrlq       $16, %%mm7 \n\t"	/* shift 1 left word to the right */
	  "paddsw    %%mm2, %%mm7 \n\t"	/* add 1 left and 1 right result words */
	  "movd      %%eax, %%mm1 \n\t"	/* save EAX in MM1 */
	  "packuswb  %%mm0, %%mm7 \n\t"	/* pack division result with saturation */
	  "movd      %%mm7, %%eax \n\t"	/* copy saturated result into EAX */
	  "mov      %%al, (%%edi) \n\t"	/* copy a byte result into Dest */
	  "movd      %%mm1, %%eax \n\t"	/* restore saved EAX */
/* -- */
	  "movd      %%mm6, %%esi \n\t"	/* move Src pointer to the top pixel */
	  "sub        $104, %%edx \n\t"	/* EDX = Kernel address */
	  "inc              %%esi \n\t"	/* move Src  pointer to the next pixel */
	  "inc              %%edi \n\t"	/* move Dest pointer to the next pixel */
/* --- */
	  "dec              %%ecx \n\t"	/* decrease loop counter COLUMNS */
	  "jnz            .L10382 \n\t"	/* check loop termination, proceed if required */
	   "add          $6, %%esi \n\t"	/* move to the next row in Src */
	  "add          $6, %%edi \n\t"	/* move to the next row in Dest */
	   "dec              %%ebx \n\t"	/* decrease loop counter ROWS */
	  "jnz            .L10380 \n\t"	/* check loop termination, proceed if required */
/* --- */
	  "emms                   \n\t"	/* exit MMX state */
	  "popa                   \n\t":"=m" (Dest)	/* %0 */
	  :"m"(Src),		/* %1 */
	  "m"(rows),		/* %2 */
	  "m"(columns),		/* %3 */
	  "m"(Kernel),		/* %4 */
	  "m"(NRightShift)	/* %5 */
	    );
#endif
	return (0);
    } else {
	/* No non-MMX implementation yet */
	return (-1);
    }
}

/*  SDL_imageFilterConvolveKernel9x9ShiftRight: Dij = saturation0and255( ... ) */
int SDL_imageFilterConvolveKernel9x9ShiftRight(unsigned char *Src, unsigned char *Dest, int rows, int columns,
					       signed short *Kernel, unsigned char NRightShift)
{
    if ((columns < 9) || (rows < 9) || (NRightShift > 7))
	return (-1);

    if ((SDL_imageFilterMMXdetect())) {
#ifdef USE_MMX
	asm volatile
	 ("pusha		     \n\t" "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 */
	   "xor       %%ebx, %%ebx \n\t"	/* zero EBX */
	  "mov           %5, %%bl \n\t"	/* load NRightShift into BL */
	  "movd      %%ebx, %%mm5 \n\t"	/* copy NRightShift into MM5 */
	   "mov          %4, %%edx \n\t"	/* load Kernel address into EDX */
	  "mov          %1, %%esi \n\t"	/* load Src  address to ESI */
	  "mov          %0, %%edi \n\t"	/* load Dest address to EDI */
	  "add          $4, %%edi \n\t"	/* 4 column offset from the left edge */
	  "mov          %3, %%eax \n\t"	/* load columns into EAX */
	  "add       %%eax, %%edi \n\t"	/* 4 row offset from the top edge */
	  "add       %%eax, %%edi \n\t" "add       %%eax, %%edi \n\t" "add       %%eax, %%edi \n\t" "mov          %2, %%ebx \n\t"	/* initialize ROWS counter */
	  "sub          $8, %%ebx \n\t"	/* do not use first 4 and last 4 rows */
/* --- */
	  ".L10390:               \n\t" "mov       %%eax, %%ecx \n\t"	/* initialize COLUMNS counter */
	  "sub          $8, %%ecx \n\t"	/* do not use first 4 and last 4 columns */
	   ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
	  ".L10392:               \n\t" "pxor      %%mm7, %%mm7 \n\t"	/* zero MM7 (accumulator) */
	  "movd      %%esi, %%mm6 \n\t"	/* save ESI in MM6 */
/* --- 1 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 2 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 3 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 4 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 5 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 6 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 7 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 8 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "dec              %%esi \n\t" "add       %%eax, %%esi \n\t"	/* move Src pointer 1 row below */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- 9 */
	  "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq      %%mm1, %%mm2 \n\t"	/* copy MM1 into MM2 */
	  "inc              %%esi \n\t"	/* move pointer to the next 8 bytes of Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	  "movq    (%%edx), %%mm4 \n\t"	/* load 4 words of Kernel */
	  "add          $8, %%edx \n\t"	/* move pointer to other 4 words */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "punpckhbw %%mm0, %%mm2 \n\t"	/* unpack second 4 bytes into words */
	   "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm5, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	   "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "pmullw    %%mm4, %%mm2 \n\t"	/* mult. 4 high words of Src and Kernel */
	   "paddsw    %%mm2, %%mm1 \n\t"	/* add 4 words of the high and low bytes */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
	   "movq    (%%esi), %%mm1 \n\t"	/* load 8 bytes of the Src */
	  "movq    (%%edx), %%mm3 \n\t"	/* load 4 words of Kernel */
	   "punpcklbw %%mm0, %%mm1 \n\t"	/* unpack first  4 bytes into words */
	  "psrlw     %%mm5, %%mm1 \n\t"	/* shift right each pixel NshiftRight times */
	  "pmullw    %%mm3, %%mm1 \n\t"	/* mult. 4 low  words of Src and Kernel */
	  "paddsw    %%mm1, %%mm7 \n\t"	/* add MM1 to accumulator MM7 */
/* --- */
	  "movq      %%mm7, %%mm3 \n\t"	/* copy MM7 into MM3 */
	  "psrlq       $32, %%mm7 \n\t"	/* shift 2 left words to the right */
	  "paddsw    %%mm3, %%mm7 \n\t"	/* add 2 left and 2 right result words */
	  "movq      %%mm7, %%mm2 \n\t"	/* copy MM7 into MM2 */
	  "psrlq       $16, %%mm7 \n\t"	/* shift 1 left word to the right */
	  "paddsw    %%mm2, %%mm7 \n\t"	/* add 1 left and 1 right result words */
	  "movd      %%eax, %%mm1 \n\t"	/* save EAX in MM1 */
	  "packuswb  %%mm0, %%mm7 \n\t"	/* pack division result with saturation */
	  "movd      %%mm7, %%eax \n\t"	/* copy saturated result into EAX */
	  "mov      %%al, (%%edi) \n\t"	/* copy a byte result into Dest */
	  "movd      %%mm1, %%eax \n\t"	/* restore saved EAX */
/* -- */
	  "movd      %%mm6, %%esi \n\t"	/* move Src pointer to the top pixel */
	  "sub        $208, %%edx \n\t"	/* EDX = Kernel address */
	  "inc              %%esi \n\t"	/* move Src  pointer to the next pixel */
	  "inc              %%edi \n\t"	/* move Dest pointer to the next pixel */
/* --- */
	  "dec              %%ecx \n\t"	/* decrease loop counter COLUMNS */
	  "jnz            .L10392 \n\t"	/* check loop termination, proceed if required */
	   "add          $8, %%esi \n\t"	/* move to the next row in Src */
	  "add          $8, %%edi \n\t"	/* move to the next row in Dest */
	   "dec              %%ebx \n\t"	/* decrease loop counter ROWS */
	  "jnz            .L10390 \n\t"	/* check loop termination, proceed if required */
/* --- */
	  "emms                   \n\t"	/* exit MMX state */
	  "popa                   \n\t":"=m" (Dest)	/* %0 */
	  :"m"(Src),		/* %1 */
	  "m"(rows),		/* %2 */
	  "m"(columns),		/* %3 */
	  "m"(Kernel),		/* %4 */
	  "m"(NRightShift)	/* %5 */
	    );
#endif
	return (0);
    } else {
	/* No non-MMX implementation yet */
	return (-1);
    }
}

/* ------------------------------------------------------------------------------------ */

/*  SDL_imageFilterSobelX: Dij = saturation255( ... ) */
int SDL_imageFilterSobelX(unsigned char *Src, unsigned char *Dest, int rows, int columns)
{
    if ((columns < 8) || (rows < 3))
	return (-1);

    if ((SDL_imageFilterMMXdetect())) {
#ifdef USE_MMX
	asm volatile
	 ("pusha		     \n\t" "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 */
	  "mov          %3, %%eax \n\t"	/* load columns into EAX */
/* --- */
	  "mov          %1, %%esi \n\t"	/* ESI = Src row 0 address */
	  "mov          %0, %%edi \n\t"	/* load Dest address to EDI */
	  "add       %%eax, %%edi \n\t"	/* EDI = EDI + columns */
	  "inc              %%edi \n\t"	/* 1 byte offset from the left edge */
	   "mov          %2, %%edx \n\t"	/* initialize ROWS counter */
	  "sub          $2, %%edx \n\t"	/* do not use first and last rows */
/* --- */
	  ".L10400:                \n\t" "mov       %%eax, %%ecx \n\t"	/* initialize COLUMS counter */
	  "shr          $3, %%ecx \n\t"	/* EBX/8 (MMX loads 8 bytes at a time) */
	   "mov       %%esi, %%ebx \n\t"	/* save ESI in EBX */
	  "movd      %%edi, %%mm1 \n\t"	/* save EDI in MM1 */
	   ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
	  ".L10402:               \n\t"
/* --- */
	  "movq    (%%esi), %%mm4 \n\t"	/* load 8 bytes from Src */
	  "movq      %%mm4, %%mm5 \n\t"	/* save MM4 in MM5 */
	  "add          $2, %%esi \n\t"	/* move ESI pointer 2 bytes right */
	  "punpcklbw %%mm0, %%mm4 \n\t"	/* unpack 4 low  bytes into words */
	  "punpckhbw %%mm0, %%mm5 \n\t"	/* unpack 4 high bytes into words */
	   "movq    (%%esi), %%mm6 \n\t"	/* load 8 bytes from Src */
	  "movq      %%mm6, %%mm7 \n\t"	/* save MM6 in MM7 */
	  "sub          $2, %%esi \n\t"	/* move ESI pointer back 2 bytes left */
	   "punpcklbw %%mm0, %%mm6 \n\t"	/* unpack 4 low  bytes into words */
	  "punpckhbw %%mm0, %%mm7 \n\t"	/* unpack 4 high bytes into words */
	   "add       %%eax, %%esi \n\t"	/* move to the next row of Src */
	   "movq    (%%esi), %%mm2 \n\t"	/* load 8 bytes from Src */
	  "movq      %%mm2, %%mm3 \n\t"	/* save MM2 in MM3 */
	  "add          $2, %%esi \n\t"	/* move ESI pointer 2 bytes right */
	  "punpcklbw %%mm0, %%mm2 \n\t"	/* unpack 4 low  bytes into words */
	  "punpckhbw %%mm0, %%mm3 \n\t"	/* unpack 4 high bytes into words */
	   "paddw     %%mm2, %%mm4 \n\t"	/* add 4 low  bytes to accumolator MM4 */
	  "paddw     %%mm3, %%mm5 \n\t"	/* add 4 high bytes to accumolator MM5 */
	  "paddw     %%mm2, %%mm4 \n\t"	/* add 4 low  bytes to accumolator MM4 */
	  "paddw     %%mm3, %%mm5 \n\t"	/* add 4 high bytes to accumolator MM5 */
	   "movq    (%%esi), %%mm2 \n\t"	/* load 8 bytes from Src */
	  "movq      %%mm2, %%mm3 \n\t"	/* save MM2 in MM3 */
	  "sub          $2, %%esi \n\t"	/* move ESI pointer back 2 bytes left */
	  "punpcklbw %%mm0, %%mm2 \n\t"	/* unpack 4 low  bytes into words */
	  "punpckhbw %%mm0, %%mm3 \n\t"	/* unpack 4 high bytes into words */
	   "paddw     %%mm2, %%mm6 \n\t"	/* add 4 low  bytes to accumolator MM6 */
	  "paddw     %%mm3, %%mm7 \n\t"	/* add 4 high bytes to accumolator MM7 */
	  "paddw     %%mm2, %%mm6 \n\t"	/* add 4 low  bytes to accumolator MM6 */
	  "paddw     %%mm3, %%mm7 \n\t"	/* add 4 high bytes to accumolator MM7 */
	   "add       %%eax, %%esi \n\t"	/* move to the next row of Src */
	   "movq    (%%esi), %%mm2 \n\t"	/* load 8 bytes from Src */
	  "movq      %%mm2, %%mm3 \n\t"	/* save MM2 in MM3 */
	  "add          $2, %%esi \n\t"	/* move ESI pointer 2 bytes right */
	  "punpcklbw %%mm0, %%mm2 \n\t"	/* unpack 4 low  bytes into words */
	  "punpckhbw %%mm0, %%mm3 \n\t"	/* unpack 4 high bytes into words */
	   "paddw     %%mm2, %%mm4 \n\t"	/* add 4 low  bytes to accumolator MM4 */
	  "paddw     %%mm3, %%mm5 \n\t"	/* add 4 high bytes to accumolator MM5 */
	   "movq    (%%esi), %%mm2 \n\t"	/* load 8 bytes from Src */
	  "movq      %%mm2, %%mm3 \n\t"	/* save MM2 in MM3 */
	  "sub          $2, %%esi \n\t"	/* move ESI pointer back 2 bytes left */
	  "punpcklbw %%mm0, %%mm2 \n\t"	/* unpack 4 low  bytes into words */
	  "punpckhbw %%mm0, %%mm3 \n\t"	/* unpack 4 high bytes into words */
	   "paddw     %%mm2, %%mm6 \n\t"	/* add 4 low  bytes to accumolator MM6 */
	  "paddw     %%mm3, %%mm7 \n\t"	/* add 4 high bytes to accumolator MM7 */
/* --- */
	  "movq      %%mm4, %%mm2 \n\t"	/* copy MM4 into MM2 */
	  "psrlq       $32, %%mm4 \n\t"	/* shift 2 left words to the right */
	  "psubw     %%mm2, %%mm4 \n\t"	/* MM4 = MM4 - MM2 */
	  "movq      %%mm6, %%mm3 \n\t"	/* copy MM6 into MM3 */
	  "psrlq       $32, %%mm6 \n\t"	/* shift 2 left words to the right */
	  "psubw     %%mm3, %%mm6 \n\t"	/* MM6 = MM6 - MM3 */
	  "punpckldq %%mm6, %%mm4 \n\t"	/* combine 2 words of MM6 and 2 words of MM4 */
	   "movq      %%mm5, %%mm2 \n\t"	/* copy MM6 into MM2 */
	  "psrlq       $32, %%mm5 \n\t"	/* shift 2 left words to the right */
	  "psubw     %%mm2, %%mm5 \n\t"	/* MM5 = MM5 - MM2 */
	  "movq      %%mm7, %%mm3 \n\t"	/* copy MM7 into MM3 */
	  "psrlq       $32, %%mm7 \n\t"	/* shift 2 left words to the right */
	  "psubw     %%mm3, %%mm7 \n\t"	/* MM7 = MM7 - MM3 */
	  "punpckldq %%mm7, %%mm5 \n\t"	/* combine 2 words of MM7 and 2 words of MM5 */
	  /* Take abs values of MM4 and MM5 */
	  "movq      %%mm4, %%mm6 \n\t"	/* copy MM4 into MM6 */
	  "movq      %%mm5, %%mm7 \n\t"	/* copy MM5 into MM7 */
	  "psraw       $15, %%mm6 \n\t"	/* fill MM6 words with word sign bit */
	  "psraw       $15, %%mm7 \n\t"	/* fill MM7 words with word sign bit */
	  "pxor      %%mm6, %%mm4 \n\t"	/* take 1's compliment of only neg. words */
	  "pxor      %%mm7, %%mm5 \n\t"	/* take 1's compliment of only neg. words */
	  "psubsw    %%mm6, %%mm4 \n\t"	/* add 1 to only neg. words, W-(-1) or W-0 */
	  "psubsw    %%mm7, %%mm5 \n\t"	/* add 1 to only neg. words, W-(-1) or W-0 */
	   "packuswb  %%mm5, %%mm4 \n\t"	/* combine and pack/saturate MM5 and MM4 */
	  "movq    %%mm4, (%%edi) \n\t"	/* store result in Dest */
/* --- */
	  "sub       %%eax, %%esi \n\t"	/* move to the current top row in Src */
	  "sub       %%eax, %%esi \n\t" "add $8,          %%esi \n\t"	/* move Src  pointer to the next 8 pixels */
	  "add $8,          %%edi \n\t"	/* move Dest pointer to the next 8 pixels */
/* --- */
	  "dec              %%ecx \n\t"	/* decrease loop counter COLUMNS */
	  "jnz            .L10402 \n\t"	/* check loop termination, proceed if required */
	   "mov       %%ebx, %%esi \n\t"	/* restore most left current row Src  address */
	  "movd      %%mm1, %%edi \n\t"	/* restore most left current row Dest address */
	  "add       %%eax, %%esi \n\t"	/* move to the next row in Src */
	  "add       %%eax, %%edi \n\t"	/* move to the next row in Dest */
	   "dec              %%edx \n\t"	/* decrease loop counter ROWS */
	  "jnz            .L10400 \n\t"	/* check loop termination, proceed if required */
/* --- */
	  "emms                   \n\t"	/* exit MMX state */
	  "popa                   \n\t":"=m" (Dest)	/* %0 */
	  :"m"(Src),		/* %1 */
	  "m"(rows),		/* %2 */
	  "m"(columns)		/* %3 */
	    );
#endif
	return (0);
    } else {
	/* No non-MMX implementation yet */
	return (-1);
    }
}

/*  SDL_imageFilterSobelXShiftRight: Dij = saturation255( ... ) */
int SDL_imageFilterSobelXShiftRight(unsigned char *Src, unsigned char *Dest, int rows, int columns,
				    unsigned char NRightShift)
{
    if ((columns < 8) || (rows < 3) || (NRightShift > 7))
	return (-1);

    if ((SDL_imageFilterMMXdetect())) {
#ifdef USE_MMX
	asm volatile
	 ("pusha		     \n\t" "pxor      %%mm0, %%mm0 \n\t"	/* zero MM0 */
	  "mov          %3, %%eax \n\t"	/* load columns into EAX */
	   "xor       %%ebx, %%ebx \n\t"	/* zero EBX */
	  "mov           %4, %%bl \n\t"	/* load NRightShift into BL */
	  "movd      %%ebx, %%mm1 \n\t"	/* copy NRightShift into MM1 */
/* --- */
	  "mov          %1, %%esi \n\t"	/* ESI = Src row 0 address */
	  "mov          %0, %%edi \n\t"	/* load Dest address to EDI */
	  "add       %%eax, %%edi \n\t"	/* EDI = EDI + columns */
	  "inc              %%edi \n\t"	/* 1 byte offset from the left edge */
	  /* initialize ROWS counter */
	  "subl            $2, %2 \n\t"	/* do not use first and last rows */
/* --- */
	  ".L10410:                \n\t" "mov       %%eax, %%ecx \n\t"	/* initialize COLUMS counter */
	  "shr          $3, %%ecx \n\t"	/* EBX/8 (MMX loads 8 bytes at a time) */
	   "mov       %%esi, %%ebx \n\t"	/* save ESI in EBX */
	  "mov       %%edi, %%edx \n\t"	/* save EDI in EDX */
	   ".align 16              \n\t"	/* 16 byte allignment of the loop entry */
	  ".L10412:               \n\t"
/* --- */
	  "movq    (%%esi), %%mm4 \n\t"	/* load 8 bytes from Src */
	  "movq      %%mm4, %%mm5 \n\t"	/* save MM4 in MM5 */
	  "add          $2, %%esi \n\t"	/* move ESI pointer 2 bytes right */
	  "punpcklbw %%mm0, %%mm4 \n\t"	/* unpack 4 low  bytes into words */
	  "punpckhbw %%mm0, %%mm5 \n\t"	/* unpack 4 high bytes into words */
	   "psrlw     %%mm1, %%mm4 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm1, %%mm5 \n\t"	/* shift right each pixel NshiftRight times */
	   "movq    (%%esi), %%mm6 \n\t"	/* load 8 bytes from Src */
	  "movq      %%mm6, %%mm7 \n\t"	/* save MM6 in MM7 */
	  "sub          $2, %%esi \n\t"	/* move ESI pointer back 2 bytes left */
	   "punpcklbw %%mm0, %%mm6 \n\t"	/* unpack 4 low  bytes into words */
	  "punpckhbw %%mm0, %%mm7 \n\t"	/* unpack 4 high bytes into words */
	   "psrlw     %%mm1, %%mm6 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm1, %%mm7 \n\t"	/* shift right each pixel NshiftRight times */
	   "add       %%eax, %%esi \n\t"	/* move to the next row of Src */
	   "movq    (%%esi), %%mm2 \n\t"	/* load 8 bytes from Src */
	  "movq      %%mm2, %%mm3 \n\t"	/* save MM2 in MM3 */
	  "add          $2, %%esi \n\t"	/* move ESI pointer 2 bytes right */
	  "punpcklbw %%mm0, %%mm2 \n\t"	/* unpack 4 low  bytes into words */
	  "punpckhbw %%mm0, %%mm3 \n\t"	/* unpack 4 high bytes into words */
	   "psrlw     %%mm1, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm1, %%mm3 \n\t"	/* shift right each pixel NshiftRight times */
	   "paddw     %%mm2, %%mm4 \n\t"	/* add 4 low  bytes to accumolator MM4 */
	  "paddw     %%mm3, %%mm5 \n\t"	/* add 4 high bytes to accumolator MM5 */
	  "paddw     %%mm2, %%mm4 \n\t"	/* add 4 low  bytes to accumolator MM4 */
	  "paddw     %%mm3, %%mm5 \n\t"	/* add 4 high bytes to accumolator MM5 */
	   "movq    (%%esi), %%mm2 \n\t"	/* load 8 bytes from Src */
	  "movq      %%mm2, %%mm3 \n\t"	/* save MM2 in MM3 */
	  "sub          $2, %%esi \n\t"	/* move ESI pointer back 2 bytes left */
	  "punpcklbw %%mm0, %%mm2 \n\t"	/* unpack 4 low  bytes into words */
	  "punpckhbw %%mm0, %%mm3 \n\t"	/* unpack 4 high bytes into words */
	   "psrlw     %%mm1, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm1, %%mm3 \n\t"	/* shift right each pixel NshiftRight times */
	   "paddw     %%mm2, %%mm6 \n\t"	/* add 4 low  bytes to accumolator MM6 */
	  "paddw     %%mm3, %%mm7 \n\t"	/* add 4 high bytes to accumolator MM7 */
	  "paddw     %%mm2, %%mm6 \n\t"	/* add 4 low  bytes to accumolator MM6 */
	  "paddw     %%mm3, %%mm7 \n\t"	/* add 4 high bytes to accumolator MM7 */
	   "add       %%eax, %%esi \n\t"	/* move to the next row of Src */
	   "movq    (%%esi), %%mm2 \n\t"	/* load 8 bytes from Src */
	  "movq      %%mm2, %%mm3 \n\t"	/* save MM2 in MM3 */
	  "add          $2, %%esi \n\t"	/* move ESI pointer 2 bytes right */
	  "punpcklbw %%mm0, %%mm2 \n\t"	/* unpack 4 low  bytes into words */
	  "punpckhbw %%mm0, %%mm3 \n\t"	/* unpack 4 high bytes into words */
	   "psrlw     %%mm1, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm1, %%mm3 \n\t"	/* shift right each pixel NshiftRight times */
	   "paddw     %%mm2, %%mm4 \n\t"	/* add 4 low  bytes to accumolator MM4 */
	  "paddw     %%mm3, %%mm5 \n\t"	/* add 4 high bytes to accumolator MM5 */
	   "movq    (%%esi), %%mm2 \n\t"	/* load 8 bytes from Src */
	  "movq      %%mm2, %%mm3 \n\t"	/* save MM2 in MM3 */
	  "sub          $2, %%esi \n\t"	/* move ESI pointer back 2 bytes left */
	  "punpcklbw %%mm0, %%mm2 \n\t"	/* unpack 4 low  bytes into words */
	  "punpckhbw %%mm0, %%mm3 \n\t"	/* unpack 4 high bytes into words */
	   "psrlw     %%mm1, %%mm2 \n\t"	/* shift right each pixel NshiftRight times */
	  "psrlw     %%mm1, %%mm3 \n\t"	/* shift right each pixel NshiftRight times */
	   "paddw     %%mm2, %%mm6 \n\t"	/* add 4 low  bytes to accumolator MM6 */
	  "paddw     %%mm3, %%mm7 \n\t"	/* add 4 high bytes to accumolator MM7 */
/* --- */
	  "movq      %%mm4, %%mm2 \n\t"	/* copy MM4 into MM2 */
	  "psrlq       $32, %%mm4 \n\t"	/* shift 2 left words to the right */
	  "psubw     %%mm2, %%mm4 \n\t"	/* MM4 = MM4 - MM2 */
	  "movq      %%mm6, %%mm3 \n\t"	/* copy MM6 into MM3 */
	  "psrlq       $32, %%mm6 \n\t"	/* shift 2 left words to the right */
	  "psubw     %%mm3, %%mm6 \n\t"	/* MM6 = MM6 - MM3 */
	  "punpckldq %%mm6, %%mm4 \n\t"	/* combine 2 words of MM6 and 2 words of MM4 */
	   "movq      %%mm5, %%mm2 \n\t"	/* copy MM6 into MM2 */
	  "psrlq       $32, %%mm5 \n\t"	/* shift 2 left words to the right */
	  "psubw     %%mm2, %%mm5 \n\t"	/* MM5 = MM5 - MM2 */
	  "movq      %%mm7, %%mm3 \n\t"	/* copy MM7 into MM3 */
	  "psrlq       $32, %%mm7 \n\t"	/* shift 2 left words to the right */
	  "psubw     %%mm3, %%mm7 \n\t"	/* MM7 = MM7 - MM3 */
	  "punpckldq %%mm7, %%mm5 \n\t"	/* combine 2 words of MM7 and 2 words of MM5 */
	  /* Take abs values of MM4 and MM5 */
	  "movq      %%mm4, %%mm6 \n\t"	/* copy MM4 into MM6 */
	  "movq      %%mm5, %%mm7 \n\t"	/* copy MM5 into MM7 */
	  "psraw       $15, %%mm6 \n\t"	/* fill MM6 words with word sign bit */
	  "psraw       $15, %%mm7 \n\t"	/* fill MM7 words with word sign bit */
	  "pxor      %%mm6, %%mm4 \n\t"	/* take 1's compliment of only neg. words */
	  "pxor      %%mm7, %%mm5 \n\t"	/* take 1's compliment of only neg. words */
	  "psubsw    %%mm6, %%mm4 \n\t"	/* add 1 to only neg. words, W-(-1) or W-0 */
	  "psubsw    %%mm7, %%mm5 \n\t"	/* add 1 to only neg. words, W-(-1) or W-0 */
	   "packuswb  %%mm5, %%mm4 \n\t"	/* combine and pack/saturate MM5 and MM4 */
	  "movq    %%mm4, (%%edi) \n\t"	/* store result in Dest */
/* --- */
	  "sub       %%eax, %%esi \n\t"	/* move to the current top row in Src */
	  "sub       %%eax, %%esi \n\t" "add $8,          %%esi \n\t"	/* move Src  pointer to the next 8 pixels */
	  "add $8,          %%edi \n\t"	/* move Dest pointer to the next 8 pixels */
/* --- */
	  "dec              %%ecx \n\t"	/* decrease loop counter COLUMNS */
	  "jnz            .L10412 \n\t"	/* check loop termination, proceed if required */
	   "mov       %%ebx, %%esi \n\t"	/* restore most left current row Src  address */
	  "mov       %%edx, %%edi \n\t"	/* restore most left current row Dest address */
	  "add       %%eax, %%esi \n\t"	/* move to the next row in Src */
	  "add       %%eax, %%edi \n\t"	/* move to the next row in Dest */
	   "decl                %2 \n\t"	/* decrease loop counter ROWS */
	  "jnz            .L10410 \n\t"	/* check loop termination, proceed if required */
/* --- */
	  "emms                   \n\t"	/* exit MMX state */
	  "popa                   \n\t":"=m" (Dest)	/* %0 */
	  :"m"(Src),		/* %1 */
	  "m"(rows),		/* %2 */
	  "m"(columns),		/* %3 */
	  "m"(NRightShift)	/* %4 */
	    );
#endif
	return (0);
    } else {
	/* No non-MMX implementation yet */
	return (-1);
    }
}

/* Align stack to 32 byte boundary */
void SDL_imageFilterAlignStack(void)
{
#ifdef USE_MMX
    asm volatile
     (				/* --- stack alignment --- */
	 "mov       %%esp, %%ebx \n\t"	/* load ESP into EBX */
	 "sub          $4, %%ebx \n\t"	/* reserve space on stack for old value of ESP */
	 "and        $-32, %%ebx \n\t"	/* align EBX along a 32 byte boundary */
	 "mov     %%esp, (%%ebx) \n\t"	/* save old value of ESP in stack, behind the bndry */
	 "mov       %%ebx, %%esp \n\t"	/* align ESP along a 32 byte boundary */
	 ::);
#endif
}

/* Restore previously aligned stack */
void SDL_imageFilterRestoreStack(void)
{
#ifdef USE_MMX
    asm volatile
     (				/* --- restoring old stack --- */
	 "mov     (%%esp), %%ebx \n\t"	/* load old value of ESP */
	 "mov       %%ebx, %%esp \n\t"	/* restore old value of ESP */
	 ::);
#endif
}
