src/audio/SDL_mixer_MMX.c
author Sam Lantinga
Mon, 06 Feb 2006 08:28:51 +0000
changeset 1330 450721ad5436
parent 1147 b580f7201543
child 1402 d910939febfa
permissions -rw-r--r--
It's now possible to build SDL without any C runtime at all on Windows,
using Visual C++ 2005
     1 /*
     2     MMX assembler version of SDL_MixAudio for signed little endian 16 bit samples and signed 8 bit samples
     3     Copyright 2002 Stephane Marchesin (stephane.marchesin@wanadoo.fr)
     4     This code is licensed under the LGPL (see COPYING for details)
     5  
     6     Assumes buffer size in bytes is a multiple of 16
     7     Assumes SDL_MIX_MAXVOLUME = 128
     8 */
     9 
    10 
    11 /***********************************************
    12 *   Mixing for 16 bit signed buffers
    13 ***********************************************/
    14 
    15 #if defined(i386) && defined(__GNUC__) && defined(USE_ASMBLIT)
    16 void SDL_MixAudio_MMX_S16(char* dst,char* src,unsigned int size,int volume)
    17 {
    18     __asm__ __volatile__ (
    19 
    20 "	movl %3,%%eax\n"	// eax = volume
    21 
    22 "	movl %2,%%edx\n"	// edx = size
    23 
    24 "	shrl $4,%%edx\n"	// process 16 bytes per iteration = 8 samples
    25 
    26 "	jz .endS16\n"
    27 
    28 "	pxor %%mm0,%%mm0\n"
    29 
    30 "	movd %%eax,%%mm0\n"
    31 "	movq %%mm0,%%mm1\n"
    32 "	psllq $16,%%mm0\n"
    33 "	por %%mm1,%%mm0\n"
    34 "	psllq $16,%%mm0\n"
    35 "	por %%mm1,%%mm0\n"
    36 "	psllq $16,%%mm0\n"
    37 "	por %%mm1,%%mm0\n"		// mm0 = vol|vol|vol|vol
    38 
    39 ".align 16\n"
    40 "	.mixloopS16:\n"
    41 
    42 "	movq (%1),%%mm1\n" // mm1 = a|b|c|d
    43 
    44 "	movq %%mm1,%%mm2\n" // mm2 = a|b|c|d
    45 
    46 "	movq 8(%1),%%mm4\n" // mm4 = e|f|g|h
    47 
    48 	// pré charger le buffer dst dans mm7
    49 "	movq (%0),%%mm7\n" // mm7 = dst[0]"
    50 
    51 	// multiplier par le volume
    52 "	pmullw %%mm0,%%mm1\n" // mm1 = l(a*v)|l(b*v)|l(c*v)|l(d*v)
    53 
    54 "	pmulhw %%mm0,%%mm2\n" // mm2 = h(a*v)|h(b*v)|h(c*v)|h(d*v)
    55 "	movq %%mm4,%%mm5\n" // mm5 = e|f|g|h
    56 
    57 "	pmullw %%mm0,%%mm4\n" // mm4 = l(e*v)|l(f*v)|l(g*v)|l(h*v)
    58 
    59 "	pmulhw %%mm0,%%mm5\n" // mm5 = h(e*v)|h(f*v)|h(g*v)|h(h*v)
    60 "	movq %%mm1,%%mm3\n" // mm3 = l(a*v)|l(b*v)|l(c*v)|l(d*v)
    61 
    62 "	punpckhwd %%mm2,%%mm1\n" // mm1 = a*v|b*v
    63 
    64 "	movq %%mm4,%%mm6\n" // mm6 = l(e*v)|l(f*v)|l(g*v)|l(h*v)
    65 "	punpcklwd %%mm2,%%mm3\n" // mm3 = c*v|d*v
    66 
    67 "	punpckhwd %%mm5,%%mm4\n" // mm4 = e*f|f*v
    68 
    69 "	punpcklwd %%mm5,%%mm6\n" // mm6 = g*v|h*v
    70 
    71 	// pré charger le buffer dst dans mm5
    72 "	movq 8(%0),%%mm5\n" // mm5 = dst[1]
    73 
    74 	// diviser par 128
    75 "	psrad $7,%%mm1\n" // mm1 = a*v/128|b*v/128 , 128 = SDL_MIX_MAXVOLUME
    76 "	add $16,%1\n"
    77 
    78 "	psrad $7,%%mm3\n" // mm3 = c*v/128|d*v/128
    79 
    80 "	psrad $7,%%mm4\n" // mm4 = e*v/128|f*v/128
    81 
    82 	// mm1 = le sample avec le volume modifié
    83 "	packssdw %%mm1,%%mm3\n" // mm3 = s(a*v|b*v|c*v|d*v)
    84 
    85 "	psrad $7,%%mm6\n" // mm6= g*v/128|h*v/128
    86 "	paddsw %%mm7,%%mm3\n" // mm3 = adjust_volume(src)+dst
    87 
    88 	// mm4 = le sample avec le volume modifié
    89 "	packssdw %%mm4,%%mm6\n" // mm6 = s(e*v|f*v|g*v|h*v)
    90 "	movq %%mm3,(%0)\n"
    91 
    92 "	paddsw %%mm5,%%mm6\n" // mm6 = adjust_volume(src)+dst
    93 
    94 "	movq %%mm6,8(%0)\n"
    95 
    96 "	add $16,%0\n"
    97 
    98 "	dec %%edx\n"
    99 
   100 "	jnz .mixloopS16\n"
   101 
   102 "	emms\n"
   103 
   104 ".endS16:\n"
   105 	 :
   106 	 : "r" (dst), "r"(src),"m"(size),
   107 	 "m"(volume)
   108 	 : "eax","edx","memory"
   109 	 );
   110 }
   111 
   112 
   113 
   114 ////////////////////////////////////////////////
   115 // Mixing for 8 bit signed buffers
   116 ////////////////////////////////////////////////
   117 
   118 void SDL_MixAudio_MMX_S8(char* dst,char* src,unsigned int size,int volume)
   119 {
   120     __asm__ __volatile__ (
   121 
   122 "	movl %3,%%eax\n"	// eax = volume
   123 
   124 "	movd %%eax,%%mm0\n"
   125 "	movq %%mm0,%%mm1\n"
   126 "	psllq $16,%%mm0\n"
   127 "	por %%mm1,%%mm0\n"
   128 "	psllq $16,%%mm0\n"
   129 "	por %%mm1,%%mm0\n"
   130 "	psllq $16,%%mm0\n"
   131 "	por %%mm1,%%mm0\n"
   132 
   133 "	movl %2,%%edx\n"	// edx = size
   134 "	shr $3,%%edx\n"	// process 8 bytes per iteration = 8 samples
   135 
   136 "	cmp $0,%%edx\n"
   137 "	je .endS8\n"
   138 
   139 ".align 16\n"
   140 "	.mixloopS8:\n"
   141 
   142 "	pxor %%mm2,%%mm2\n"		// mm2 = 0
   143 "	movq (%1),%%mm1\n"	// mm1 = a|b|c|d|e|f|g|h
   144 
   145 "	movq %%mm1,%%mm3\n" 	// mm3 = a|b|c|d|e|f|g|h
   146 
   147 	// on va faire le "sign extension" en faisant un cmp avec 0 qui retourne 1 si <0, 0 si >0
   148 "	pcmpgtb %%mm1,%%mm2\n"	// mm2 = 11111111|00000000|00000000....
   149 
   150 "	punpckhbw %%mm2,%%mm1\n"	// mm1 = 0|a|0|b|0|c|0|d
   151 
   152 "	punpcklbw %%mm2,%%mm3\n"	// mm3 = 0|e|0|f|0|g|0|h
   153 "	movq (%0),%%mm2\n"	// mm2 = destination
   154 
   155 "	pmullw %%mm0,%%mm1\n"	// mm1 = v*a|v*b|v*c|v*d
   156 "	add $8,%1\n"
   157 
   158 "	pmullw %%mm0,%%mm3\n"	// mm3 = v*e|v*f|v*g|v*h
   159 "	psraw $7,%%mm1\n"		// mm1 = v*a/128|v*b/128|v*c/128|v*d/128 
   160 
   161 "	psraw $7,%%mm3\n"		// mm3 = v*e/128|v*f/128|v*g/128|v*h/128
   162 
   163 "	packsswb %%mm1,%%mm3\n"	// mm1 = v*a/128|v*b/128|v*c/128|v*d/128|v*e/128|v*f/128|v*g/128|v*h/128
   164 
   165 "	paddsb %%mm2,%%mm3\n"	// add to destination buffer
   166 
   167 "	movq %%mm3,(%0)\n"	// store back to ram
   168 "	add $8,%0\n"
   169 
   170 "	dec %%edx\n"
   171 
   172 "	jnz .mixloopS8\n"
   173 
   174 ".endS8:\n"
   175 "	emms\n"
   176 	 :
   177 	 : "r" (dst), "r"(src),"m"(size),
   178 	 "m"(volume)
   179 	 : "eax","edx","memory"
   180 	 );
   181 }
   182 #endif
   183