| /* mmx.c |
| |
| MultiMedia eXtensions GCC interface library for IA32. |
| |
| To use this library, simply include this header file |
| and compile with GCC. You MUST have inlining enabled |
| in order for mmx_ok() to work; this can be done by |
| simply using -O on the GCC command line. |
| |
| Compiling with -DMMX_TRACE will cause detailed trace |
| output to be sent to stderr for each mmx operation. |
| This adds lots of code, and obviously slows execution to |
| a crawl, but can be very useful for debugging. |
| |
| THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY |
| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT |
| LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
| AND FITNESS FOR ANY PARTICULAR PURPOSE. |
| |
| 1997-99 by H. Dietz and R. Fisher |
| |
| Notes: |
| It appears that the latest gas has the pand problem fixed, therefore |
| I'll undefine BROKEN_PAND by default. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include "goom_config.h" |
| |
| #ifdef HAVE_MMX |
| |
| #define BUFFPOINTNB 16 |
| #define BUFFPOINTMASK 0xffff |
| #define BUFFINCR 0xff |
| |
| #include "mmx.h" |
| #include "goom_graphic.h" |
| |
| #define sqrtperte 16 |
| // faire : a % sqrtperte <=> a & pertemask |
| #define PERTEMASK 0xf |
| // faire : a / sqrtperte <=> a >> PERTEDEC |
| #define PERTEDEC 4 |
| |
| int |
| mmx_supported (void) |
| { |
| return (mm_support () & 0x1); |
| } |
| |
| void |
| zoom_filter_mmx (int prevX, int prevY, |
| Pixel * expix1, Pixel * expix2, |
| int *brutS, int *brutD, int buffratio, int precalCoef[16][16]) |
| { |
| unsigned int ax = (prevX - 1) << PERTEDEC, ay = (prevY - 1) << PERTEDEC; |
| |
| int bufsize = prevX * prevY; |
| int loop; |
| |
| __asm__ __volatile__ ("pxor %mm7,%mm7"); |
| |
| for (loop = 0; loop < bufsize; loop++) { |
| /* int couleur; */ |
| int px, py; |
| int pos; |
| int coeffs; |
| |
| int myPos = loop << 1, myPos2 = myPos + 1; |
| int brutSmypos = brutS[myPos]; |
| |
| px = brutSmypos + (((brutD[myPos] - |
| brutSmypos) * buffratio) >> BUFFPOINTNB); |
| brutSmypos = brutS[myPos2]; |
| py = brutSmypos + (((brutD[myPos2] - |
| brutSmypos) * buffratio) >> BUFFPOINTNB); |
| |
| if ((py >= ay) || (px >= ax)) { |
| pos = coeffs = 0; |
| } else { |
| pos = ((px >> PERTEDEC) + prevX * (py >> PERTEDEC)); |
| // coef en modulo 15 |
| coeffs = precalCoef[px & PERTEMASK][py & PERTEMASK]; |
| } |
| |
| __asm__ __volatile__ ("movd %2, %%mm6 \n\t" |
| /* recuperation des deux premiers pixels dans mm0 et mm1 */ |
| "movq (%3,%1,4), %%mm0 \n\t" /* b1-v1-r1-a1-b2-v2-r2-a2 */ |
| "movq %%mm0, %%mm1 \n\t" /* b1-v1-r1-a1-b2-v2-r2-a2 */ |
| /* depackage du premier pixel */ |
| "punpcklbw %%mm7, %%mm0 \n\t" /* 00-b2-00-v2-00-r2-00-a2 */ |
| "movq %%mm6, %%mm5 \n\t" /* ??-??-??-??-c4-c3-c2-c1 */ |
| /* depackage du 2ieme pixel */ |
| "punpckhbw %%mm7, %%mm1 \n\t" /* 00-b1-00-v1-00-r1-00-a1 */ |
| /* extraction des coefficients... */ |
| "punpcklbw %%mm5, %%mm6 \n\t" /* c4-c4-c3-c3-c2-c2-c1-c1 */ |
| "movq %%mm6, %%mm4 \n\t" /* c4-c4-c3-c3-c2-c2-c1-c1 */ |
| "movq %%mm6, %%mm5 \n\t" /* c4-c4-c3-c3-c2-c2-c1-c1 */ |
| "punpcklbw %%mm5, %%mm6 \n\t" /* c2-c2-c2-c2-c1-c1-c1-c1 */ |
| "punpckhbw %%mm5, %%mm4 \n\t" /* c4-c4-c4-c4-c3-c3-c3-c3 */ |
| "movq %%mm6, %%mm3 \n\t" /* c2-c2-c2-c2-c1-c1-c1-c1 */ |
| "punpcklbw %%mm7, %%mm6 \n\t" /* 00-c1-00-c1-00-c1-00-c1 */ |
| "punpckhbw %%mm7, %%mm3 \n\t" /* 00-c2-00-c2-00-c2-00-c2 */ |
| /* multiplication des pixels par les coefficients */ |
| "pmullw %%mm6, %%mm0 \n\t" /* c1*b2-c1*v2-c1*r2-c1*a2 */ |
| "pmullw %%mm3, %%mm1 \n\t" /* c2*b1-c2*v1-c2*r1-c2*a1 */ |
| "paddw %%mm1, %%mm0 \n\t" |
| /* ...extraction des 2 derniers coefficients */ |
| "movq %%mm4, %%mm5 \n\t" /* c4-c4-c4-c4-c3-c3-c3-c3 */ |
| "punpcklbw %%mm7, %%mm4 \n\t" /* 00-c3-00-c3-00-c3-00-c3 */ |
| "punpckhbw %%mm7, %%mm5 \n\t" /* 00-c4-00-c4-00-c4-00-c4 */ |
| /* ajouter la longueur de ligne a esi */ |
| "addl 8(%%ebp),%1 \n\t" |
| /* recuperation des 2 derniers pixels */ |
| "movq (%3,%1,4), %%mm1 \n\t" "movq %%mm1, %%mm2 \n\t" |
| /* depackage des pixels */ |
| "punpcklbw %%mm7, %%mm1 \n\t" "punpckhbw %%mm7, %%mm2 \n\t" |
| /* multiplication pas les coeffs */ |
| "pmullw %%mm4, %%mm1 \n\t" "pmullw %%mm5, %%mm2 \n\t" |
| /* ajout des valeurs obtenues ? la valeur finale */ |
| "paddw %%mm1, %%mm0 \n\t" "paddw %%mm2, %%mm0 \n\t" |
| /* division par 256 = 16+16+16+16, puis repackage du pixel final */ |
| "psrlw $8, %%mm0 \n\t" |
| "packuswb %%mm7, %%mm0 \n\t" "movd %%mm0,%0 \n\t":"=g" (expix2[loop]) |
| :"r" (pos), "r" (coeffs), "r" (expix1) |
| |
| ); |
| |
| emms (); |
| } |
| } |
| |
| #define DRAWMETHOD_PLUS_MMX(_out,_backbuf,_col) \ |
| { \ |
| movd_m2r(_backbuf, mm0); \ |
| paddusb_m2r(_col, mm0); \ |
| movd_r2m(mm0, _out); \ |
| } |
| |
| #define DRAWMETHOD DRAWMETHOD_PLUS_MMX(*p,*p,col) |
| |
| void |
| draw_line_mmx (Pixel * data, int x1, int y1, int x2, int y2, int col, |
| int screenx, int screeny) |
| { |
| int x, y, dx, dy, yy, xx; |
| Pixel *p; |
| |
| if ((y1 < 0) || (y2 < 0) || (x1 < 0) || (x2 < 0) || (y1 >= screeny) |
| || (y2 >= screeny) || (x1 >= screenx) || (x2 >= screenx)) |
| goto end_of_line; |
| |
| dx = x2 - x1; |
| dy = y2 - y1; |
| if (x1 >= x2) { |
| int tmp; |
| |
| tmp = x1; |
| x1 = x2; |
| x2 = tmp; |
| tmp = y1; |
| y1 = y2; |
| y2 = tmp; |
| dx = x2 - x1; |
| dy = y2 - y1; |
| } |
| |
| /* vertical line */ |
| if (dx == 0) { |
| if (y1 < y2) { |
| p = &(data[(screenx * y1) + x1]); |
| for (y = y1; y <= y2; y++) { |
| DRAWMETHOD; |
| p += screenx; |
| } |
| } else { |
| p = &(data[(screenx * y2) + x1]); |
| for (y = y2; y <= y1; y++) { |
| DRAWMETHOD; |
| p += screenx; |
| } |
| } |
| goto end_of_line; |
| } |
| /* horizontal line */ |
| if (dy == 0) { |
| if (x1 < x2) { |
| p = &(data[(screenx * y1) + x1]); |
| for (x = x1; x <= x2; x++) { |
| DRAWMETHOD; |
| p++; |
| } |
| goto end_of_line; |
| } else { |
| p = &(data[(screenx * y1) + x2]); |
| for (x = x2; x <= x1; x++) { |
| DRAWMETHOD; |
| p++; |
| } |
| goto end_of_line; |
| } |
| } |
| /* 1 */ |
| /* \ */ |
| /* \ */ |
| /* 2 */ |
| if (y2 > y1) { |
| /* steep */ |
| if (dy > dx) { |
| dx = ((dx << 16) / dy); |
| x = x1 << 16; |
| for (y = y1; y <= y2; y++) { |
| xx = x >> 16; |
| p = &(data[(screenx * y) + xx]); |
| DRAWMETHOD; |
| if (xx < (screenx - 1)) { |
| p++; |
| /* DRAWMETHOD; */ |
| } |
| x += dx; |
| } |
| goto end_of_line; |
| } |
| /* shallow */ |
| else { |
| dy = ((dy << 16) / dx); |
| y = y1 << 16; |
| for (x = x1; x <= x2; x++) { |
| yy = y >> 16; |
| p = &(data[(screenx * yy) + x]); |
| DRAWMETHOD; |
| if (yy < (screeny - 1)) { |
| p += screeny; |
| /* DRAWMETHOD; */ |
| } |
| y += dy; |
| } |
| } |
| } |
| /* 2 */ |
| /* / */ |
| /* / */ |
| /* 1 */ |
| else { |
| /* steep */ |
| if (-dy > dx) { |
| dx = ((dx << 16) / -dy); |
| x = (x1 + 1) << 16; |
| for (y = y1; y >= y2; y--) { |
| xx = x >> 16; |
| p = &(data[(screenx * y) + xx]); |
| DRAWMETHOD; |
| if (xx < (screenx - 1)) { |
| p--; |
| /* DRAWMETHOD; */ |
| } |
| x += dx; |
| } |
| goto end_of_line; |
| } |
| /* shallow */ |
| else { |
| dy = ((dy << 16) / dx); |
| y = y1 << 16; |
| for (x = x1; x <= x2; x++) { |
| yy = y >> 16; |
| p = &(data[(screenx * yy) + x]); |
| DRAWMETHOD; |
| if (yy < (screeny - 1)) { |
| p += screeny; |
| /* DRAWMETHOD; */ |
| } |
| y += dy; |
| } |
| goto end_of_line; |
| } |
| } |
| end_of_line: |
| emms (); |
| /* __asm__ __volatile__ ("emms"); */ |
| } |
| #else |
| int |
| mmx_supported (void) |
| { |
| return (0); |
| } |
| #endif /* HAVE_MMX */ |