asm optimization for 8bpp (no mmx)
[wmaker-crm.git] / wrlib / x86_specific.c
blob9ff60e2d9850075f536dce9f147247de75ae4e4f
1 /* x86_convert.c - convert RImage to XImage with x86 optimizations
2 *
3 * Raster graphics library
5 * Copyright (c) 2000 Alfredo K. Kojima
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <config.h>
24 #ifdef ASM_X86
27 #ifdef ASM_X86_MMX
29 int
30 x86_check_mmx()
32 static int result = -1;
34 if (result >= 0)
35 return result;
37 result = 0;
39 asm volatile
40 ("pushal \n" // please don't forget this in any asm
41 "pushfl \n" // check whether cpuid supported
42 "pop %%eax \n"
43 "movl %%eax, %%ebx \n"
44 "xorl $(1<<21), %%eax \n"
45 "pushl %%eax \n"
46 "popfl \n"
47 "pushfl \n"
48 "popl %%eax \n"
49 "xorl %%ebx, %%eax \n"
50 "andl $(1<<21), %%eax \n"
51 "jz .NotPentium \n"
52 "xorl %%eax, %%eax \n" // no eax effect because of the movl below
53 // except reseting flags. is it needed?
54 "movl $1, %%eax \n"
55 "cpuid \n"
56 "test $(1<<23), %%edx \n"
57 "jz .NotMMX \n"
59 "popal \n" // this is needed because the address of
60 "movl $1, %0 \n" // variable %0 may be kept in a register
61 "jmp .noPop \n"
63 ".NotMMX: \n"
64 ".NotPentium: \n"
65 "popal \n"
66 ".noPop: \n"
68 : "=m" (result));
70 return result;
75 * TODO:
76 * 32/8 24/8 32/16 24/16 32/24 24/24
77 * PPlain YES YES
78 * MMX DONE
81 * - try to align stack (local variable space) into quadword boundary
87 void
88 x86_mmx_TrueColor_32_to_16(unsigned char *image, // 8
89 unsigned short *ximage, // 12
90 short *err, // 16
91 short *nerr, // 20
92 short *rtable, // 24
93 short *gtable, // 28
94 short *btable, // 32
95 int dr, // 36
96 int dg, // 40
97 int db, // 44
98 unsigned int roffs, // 48
99 unsigned int goffs, // 52
100 unsigned int boffs, // 56
101 int width, // 60
102 int height, // 64
103 int line_offset) // 68
106 int x; //-4
107 long long rrggbbaa;// -16
108 long long pixel; //-24
109 short *tmp_err; //-32
110 short *tmp_nerr; //-36
113 asm volatile
115 "subl $128, %esp \n" // alloc some more stack
117 "pushal \n"
119 // pack dr, dg and db into mm6
120 "movl 36(%ebp), %eax \n"
121 "movl 40(%ebp), %ebx \n"
122 "movw %ax, -16(%ebp) \n"
124 "movw %bx, -14(%ebp) \n"
125 "movl 44(%ebp), %eax \n"
126 "movw $0, -10(%ebp) \n"
127 "movw %ax, -12(%ebp) \n"
129 "movq -16(%ebp), %mm6 \n" // dr dg db 0
131 // pack 4|4|4|4 into mm7, for shifting (/16)
132 "movl $0x00040004, -16(%ebp) \n"
133 "movl $0x00040004, -12(%ebp) \n"
134 "movq -16(%ebp), %mm7 \n"
136 // store constant values for using with mmx when dithering
137 "movl $0x00070007, -16(%ebp) \n"
138 "movl $0x00070007, -12(%ebp) \n"
139 "movq -16(%ebp), %mm5 \n"
141 "movl $0x00050005, -16(%ebp) \n"
142 "movl $0x00050005, -12(%ebp) \n"
143 "movq -16(%ebp), %mm4 \n"
145 "movl $0x00030003, -16(%ebp) \n"
146 "movl $0x00030003, -12(%ebp) \n"
147 "movq -16(%ebp), %mm3 \n"
149 // process 1 pixel / cycle, each component treated as 16bit
150 "movl 8(%ebp), %esi \n" // esi = image->data
152 ".LoopYa: \n"
153 "movl 60(%ebp), %eax \n"
154 "movl %eax, -4(%ebp) \n" // x = width
156 "movl 64(%ebp), %eax \n"
157 "decl %eax \n" // y--
158 "movl %eax, 64(%ebp) \n"
159 "js .Enda \n" // if y < 0, goto end
160 "andl $1, %eax \n"
161 "jz .LoopY_1a \n" // if (y&1) goto LoopY_1
163 ".LoopY_0a: \n"
165 "movl 16(%ebp), %ebx \n" // ebx = err
166 "movl %ebx, -36(%ebp) \n" // [-36] = err
167 "movl 20(%ebp), %eax \n" //
168 "movl %eax, -32(%ebp) \n" // [-32] = nerr
170 "jmp .LoopXa \n"
172 ".LoopY_1a: \n"
174 "movl 20(%ebp), %ebx \n" // ebx = nerr
175 "movl %ebx, -36(%ebp) \n" // [-36] = nerr
176 "movl 16(%ebp), %eax \n" //
177 "movl %eax, -32(%ebp) \n" // [-32] = eerr
179 ".align 16 \n"
180 ".LoopXa: \n"
182 // calculate errors and pixel components
184 // depend on ebx, esi, mm6
185 "movq (%ebx), %mm1 \n" // mm1 = error[0..3]
186 "punpcklbw (%esi), %mm0 \n" // mm0 = image->data[0..3]
187 "psrlw $8, %mm0 \n" // fixup mm0
188 "paddusb %mm1, %mm0 \n" // mm0 = mm0 + mm1 (sat. to 255)
189 "movq %mm0, -24(%ebp) \n" // save the pixel
191 "movzwl -24(%ebp), %ecx \n" // ecx = pixel.red
192 "movl 24(%ebp), %edi \n" // edi = rtable
193 "leal (%edi, %ecx, 2), %eax \n" // eax = &rtable[pixel.red]
194 "movw (%eax), %dx \n" // dx = rtable[pixel.red]
195 "movw %dx, -16(%ebp) \n" // save rr
197 "movzwl -22(%ebp), %ecx \n" // ecx = pixel.green
198 "movl 28(%ebp), %edi \n" // edi = gtable
199 "leal (%edi, %ecx, 2), %eax \n" // eax = &gtable[pixel.green]
200 "movw (%eax), %dx \n" // dx = gtable[pixel.green]
201 "movw %dx, -14(%ebp) \n" // save gg
203 "movzwl -20(%ebp), %ecx \n" // ecx = pixel.blue
204 "movl 32(%ebp), %edi \n" // ebx = btable
205 "leal (%edi, %ecx, 2), %eax \n" // eax = &btable[pixel.blue]
206 "movw (%eax), %dx \n" // dx = btable[pixel.blue]
207 "movw %dx, -12(%ebp) \n" // save bb
209 "movw $0, -10(%ebp) \n" // save dummy aa
211 "movq -16(%ebp), %mm1 \n" // load mm1 with rrggbbaa
212 "pmullw %mm6, %mm1 \n" // mm1 = rr*dr|...
213 "psubsw %mm1, %mm0 \n" // error = pixel - mm1
216 // distribute the error
218 // depend on mm0, mm7, mm3, mm4, mm5
220 "movl -36(%ebp), %ebx \n"
222 "movq %mm0, %mm1 \n"
223 "pmullw %mm5, %mm1 \n" // mm1 = mm1*7
224 "psrlw %mm7, %mm1 \n" // mm1 = mm1/16
225 "paddw 8(%ebx), %mm1 \n"
226 "movq %mm1, 8(%ebx) \n" // err[x+1,y] = rer*7/16
229 "movl -32(%ebp), %ebx \n"
231 "movq %mm0, %mm1 \n"
232 "pmullw %mm4, %mm1 \n" // mm1 = mm1*5
233 "psrlw %mm7, %mm1 \n" // mm1 = mm1/16
234 "paddw -8(%ebx), %mm1 \n"
235 "movq %mm1, -8(%ebx) \n" // err[x-1,y+1] += rer*3/16
237 "movq %mm0, %mm1 \n"
238 "pmullw %mm3, %mm1 \n" // mm1 = mm1*3
239 "psrlw %mm7, %mm1 \n" // mm1 = mm1/16
240 "paddw 8(%ebx), %mm1 \n"
241 "movq %mm1, (%ebx) \n" // err[x,y+1] += rer*5/16
243 "psrlw %mm7, %mm0 \n" // mm0 = mm0/16
244 "movq %mm0, 8(%ebx) \n" // err[x+1,y+1] = rer/16
247 // calculate final pixel value and store
248 "movl 48(%ebp), %ecx \n"
249 "movw -16(%ebp), %ax \n"
250 "shlw %cl, %ax \n" //NP* ax = r<<roffs
252 "movl 52(%ebp), %ecx \n"
253 "movw -14(%ebp), %bx \n"
254 "shlw %cl, %bx \n" //NP*
255 "orw %bx, %ax \n"
257 "movl 56(%ebp), %ecx \n"
258 "movw -12(%ebp), %bx \n"
259 "shlw %cl, %bx \n" //NP*
260 "orw %bx, %ax \n"
262 "movl 12(%ebp), %edx \n"
263 "movw %ax, (%edx) \n"
264 "addl $2, %edx \n" // increment ximage
265 "movl %edx, 12(%ebp) \n"
267 // prepare for next iteration on X
269 "addl $8, -32(%ebp) \n" // nerr += 8
271 "movl -36(%ebp), %ebx \n"
272 "addl $8, %ebx \n"
273 "movl %ebx, -36(%ebp) \n" // ebx = err += 8
276 // Note: in the last pixel, this would cause an invalid memory access
277 // because, punpcklbw is used (which reads 8 bytes) and the last
278 // pixel is only 4 bytes. This is no problem because the image data
279 // was allocated with extra 4 bytes when created.
280 "addl $4, %esi \n" // image->data += 4
283 "decl -4(%ebp) \n" // x--
284 "jnz .LoopXa \n" // if x>0, goto .LoopX
287 // depend on edx
288 "addl 68(%ebp), %edx \n" // add extra offset to ximage
289 "movl %edx, 12(%ebp) \n"
292 "jmp .LoopYa \n"
294 ".Enda: \n" // THE END
296 "emms \n"
298 "popal \n"
303 #endif /* ASM_X86_MMX */
307 void
308 x86_PseudoColor_to_8(unsigned char *image, // 8
309 unsigned char *ximage, // 12
310 char *err, // 16
311 char *nerr, // 20
312 short *ctable, // 24
313 int dr, // 28
314 int dg, // 32
315 int db, // 36
316 unsigned long *pixels, // 40
317 int cpc, // 44
318 int width, // 48
319 int height, // 52
320 int bytesPerPixel, // 56
321 int line_offset) // 60
324 * int x; -4
325 * int cpcpc; -8
327 * int rr; -12
328 * int gg; -16
329 * int bb; -20
331 * char ndr; -21
332 * char ndg; -22
333 * char ndb; -23
335 * char *err; -32
336 * char *nerr; -36
339 asm volatile
341 "subl $128, %esp \n" // alloc some stack space
342 "pushal \n"
344 "movl 44(%ebp), %eax \n"
345 "mulb 44(%ebp) \n"
346 "movl %eax, -8(%ebp) \n" // cpcpc = cpc*cpc
348 // eax will always be <= 0xffff
350 // process 1 pixel / cycle, each component treated as 16bit
351 "movl 8(%ebp), %esi \n" // esi = image->data
353 ".LoopYb: \n"
354 "movl 48(%ebp), %ecx \n"
355 "movl %ecx, -4(%ebp) \n" // x = width
357 "movl 52(%ebp), %ecx \n"
358 "decl %ecx \n" // y--
359 "movl %ecx, 52(%ebp) \n"
360 "js .Endb \n" // if y < 0, goto end
361 "andl $1, %ecx \n"
362 "jz .LoopY_1b \n" // if (y&1) goto LoopY_1
364 ".LoopY_0b: \n"
366 "movl 16(%ebp), %ebx \n" // ebx = err
367 // "movl %ebx, -36(%ebp) \n" // [-36] = err
368 "movl 20(%ebp), %ecx \n" //
369 "movl %ecx, -32(%ebp) \n" // [-32] = nerr
371 "movl $0, (%ecx) \n" // init error of nerr[0] to 0
373 "jmp .LoopXb \n"
375 ".LoopY_1b: \n"
377 "movl 20(%ebp), %ebx \n" // ebx = nerr
378 // "movl %ebx, -36(%ebp) \n" // [-36] = nerr
379 "movl 16(%ebp), %ecx \n" //
380 "movl %ecx, -32(%ebp) \n" // [-32] = err
382 "movl $0, (%ecx) \n" // init error of nerr[0] to 0
385 ".align 16 \n"
386 ".LoopXb: \n"
389 "movl 24(%ebp), %edi \n" // edi = ctable
390 "xorl %edx, %edx \n" // zero the upper word on edx
392 // RED
394 // depends on ebx==err, esi==image->data, edi
395 "movzbw (%esi), %dx \n" // dx = image->data[0]
396 "movsbw (%ebx), %ax \n" // ax = error[0]
397 "addw %ax, %dx \n" // pixel.red = data[0] + error[0]
399 "testb %dh, %dh \n" // test if pixel.red < 0 or > 255
400 "jz .OKRb \n" // 0 <= pixel.red <= 255
401 "js .NEGRb \n" // pixel.red < 0
402 "movw $0xff, %dx \n" // pixel.red > 255
403 "jmp .OKRb \n"
404 ".NEGRb: \n"
405 "xorw %dx, %dx \n"
406 ".OKRb: \n"
407 "leal (%edi, %edx, 2), %ecx \n" // ecx = &ctable[pixel.red]
408 "movl (%ecx), %eax \n" // ax = ctable[pixel.red]
409 "movw %ax, -12(%ebp) \n" // save rr
411 "mulb 28(%ebp) \n" // ax = rr*dr
412 "subw %ax, %dx \n" // rer = dx = dx - rr*dr
414 "movswl %dx, %eax \n" // save rer
416 // distribute error
417 "leal (, %eax, 8), %ecx \n"
418 "subw %dx, %cx \n" // cx = rer * 7
419 "sarw $4, %cx \n" // cx = rer * 7 / 16
420 "addb %cl, 4(%ebx) \n" // err[x+1] += rer * 7 / 16
422 "movl -32(%ebp), %ecx \n" // ecx = nerr
424 "leaw (%eax, %eax, 4), %dx \n" // dx = rer * 5
425 "sarw $4, %dx \n" // dx = rer * 5 / 16
426 "addb %dl, (%ecx) \n" // nerr[x] += rer * 5 / 16
428 "leaw (%eax, %eax, 2), %dx \n" // dx = rer * 3
429 "sarw $4, %dx \n" // dx = rer * 3 / 16
430 "addb %dl, -4(%ecx) \n" // nerr[x-1] += rer * 3 / 16
432 "sarw $4, %ax \n" // ax = rer / 16
433 "movb %al, 4(%ecx) \n" // nerr[x+1] = rer / 16
436 // GREEN
438 // depends on ebx, esi, edi
439 "movzbw 1(%esi), %dx \n" // dx = image->data[1]
440 "movsbw 1(%ebx), %ax \n" // ax = error[1]
441 "addw %ax, %dx \n" // pixel.grn = data[1] + error[1]
443 "testb %dh, %dh \n" // test if pixel.grn < 0 or > 255
444 "jz .OKGb \n" // 0 <= pixel.grn <= 255
445 "js .NEGGb \n" // pixel.grn < 0
446 "movw $0xff, %dx \n" // pixel.grn > 255
447 "jmp .OKGb \n"
448 ".NEGGb: \n"
449 "xorw %dx, %dx \n"
450 ".OKGb: \n"
451 "leal (%edi, %edx, 2), %ecx \n" // ecx = &ctable[pixel.grn]
452 "movw (%ecx), %ax \n" // ax = ctable[pixel.grn]
453 "movw %ax, -16(%ebp) \n" // save gg
455 "mulb 28(%ebp) \n" // ax = gg*dg
456 "subw %ax, %dx \n" // ger = dx = dx - gg*dg
458 "movswl %dx, %eax \n" // save ger
460 // distribute error
462 "leal (, %eax, 8), %ecx \n"
463 "subw %dx, %cx \n" // cx = ger * 7
464 "sarw $4, %cx \n" // cx = ger * 7 / 16
465 "addb %cl, 5(%ebx) \n" // err[x+1] += ger * 7 / 16
467 "movl -32(%ebp), %ecx \n" // ecx = nerr
469 "leaw (%eax, %eax, 4), %dx \n" // dx = ger * 5
470 "sarw $4, %dx \n" // dx = ger * 5 / 16
471 "addb %dl, 1(%ecx) \n" // nerr[x] += ger * 5 / 16
473 "leaw (%eax, %eax, 2), %dx \n" // dx = ger * 3
474 "sarw $4, %dx \n" // dx = ger * 3 / 16
475 "addb %dl, -3(%ecx) \n" // nerr[x-1] += ger * 3 / 16
477 "sarw $4, %ax \n" // ax = ger / 16
478 "movb %al, 5(%ecx) \n" // nerr[x+1] = ger / 16
481 // BLUE
483 // depends on ebx, esi
484 "movzbw 2(%esi), %dx \n" // dx = image->data[2]
485 "movsbw 2(%ebx), %ax \n" // ax = error[2]
486 "addw %ax, %dx \n" // pixel.grn = data[2] + error[2]
488 "testb %dh, %dh \n" // test if pixel.blu < 0 or > 255
489 "jz .OKBb \n" // 0 <= pixel.blu <= 255
490 "js .NEGBb \n" // pixel.blu < 0
491 "movw $0xff, %dx \n" // pixel.blu > 255
492 "jmp .OKBb \n"
493 ".NEGBb: \n"
494 "xorw %dx, %dx \n"
495 ".OKBb: \n"
496 "leal (%edi, %edx, 2), %ecx \n" // ecx = &ctable[pixel.blu]
497 "movw (%ecx), %ax \n" // ax = ctable[pixel.blu]
498 "movw %ax, -20(%ebp) \n" // save bb
500 "mulb 28(%ebp) \n" // ax = bb*db
501 "subw %ax, %dx \n" // ber = dx = dx - bb*db
502 "movswl %dx, %eax \n" // save ber
504 // distribute error
505 "leal (, %eax, 8), %ecx \n"
506 "subw %dx, %cx \n" // cx = ber * 7
507 "sarw $4, %cx \n" // cx = ber * 7 / 16
508 "addb %cl, 6(%ebx) \n" // err[x+1] += ber * 7 / 16
510 "movl -32(%ebp), %ecx \n" // ecx = nerr
512 "leaw (%eax, %eax, 4), %dx \n" // dx = ber * 5
513 "sarw $4, %dx \n" // dx = ber * 5 / 16
514 "addb %dl, 2(%ecx) \n" // nerr[x] += ber * 5 / 16
516 "leaw (%eax, %eax, 2), %dx \n" // dx = ber * 3
517 "sarw $4, %dx \n" // dx = ber * 3 / 16
518 "addb %dl, -4(%ecx) \n" // nerr[x-1] += ber * 3 / 16
520 "sarw $4, %ax \n" // ax = ber / 16
521 "movb %al, 6(%ecx) \n" // nerr[x+1] = ber / 16
523 "andl $0xffff, %eax \n"
524 // depends on eax & 0xffff0000 == 0
525 // calculate the index of the value of the pixel
526 "movw -12(%ebp), %ax \n" // ax = rr
527 "mulb -8(%ebp) \n" // ax = cpcpc*rr
528 "movw %ax, %cx \n"
529 "movw -16(%ebp), %ax \n" // ax = gg
530 "mulb 44(%ebp) \n" // ax = cpc*gg
531 "addw %cx, %ax \n" // ax = cpc*gg + cpcpc*rr
532 "addw -20(%ebp), %ax \n" // ax = cpcpc*rr + cpc*gg + bb
534 "movl 40(%ebp), %ecx \n"
535 "leal (%ecx, %eax, 4), %edx \n"
536 "movb (%edx), %cl \n" // cl = pixels[ax]
538 // store the pixel
539 "movl 12(%ebp), %eax \n"
540 "movb %cl, (%eax) \n" // *ximage = cl
541 "incl 12(%ebp) \n" // ximage++
543 // prepare for next iteration on X
545 "addl $4, -32(%ebp) \n" // nerr += 4
546 "addl $4, %ebx \n" // err += 4
548 "addl 56(%ebp), %esi \n" // image->data += bpp
550 "decl -4(%ebp) \n" // x--
551 "jnz .LoopXb \n" // if x>0, goto .LoopX
554 "movl 60(%ebp), %eax \n"
555 "addl %eax, 12(%ebp) \n" // add extra offset to ximage
557 "jmp .LoopYb \n"
559 ".Endb: \n"
561 "emms \n"
562 "popal \n"
568 #endif /* ASM_X86 */