syslinux-3.08-2 sources from FC4
[bootcd.git] / syslinux / com32 / lib / libpng / pngvcrd.c
1 /* pngvcrd.c - mixed C/assembler version of utilities to read a PNG file
2  *
3  * For Intel x86 CPU and Microsoft Visual C++ compiler
4  *
5  * libpng version 1.2.8 - December 3, 2004
6  * For conditions of distribution and use, see copyright notice in png.h
7  * Copyright (c) 1998-2004 Glenn Randers-Pehrson
8  * Copyright (c) 1998, Intel Corporation
9  *
10  * Contributed by Nirav Chhatrapati, Intel Corporation, 1998
11  * Interface to libpng contributed by Gilles Vollant, 1999
12  *
13  *
14  * In png_do_read_interlace() in libpng versions 1.0.3a through 1.0.4d,
15  * a sign error in the post-MMX cleanup code for each pixel_depth resulted
16  * in bad pixels at the beginning of some rows of some images, and also
17  * (due to out-of-range memory reads and writes) caused heap corruption
18  * when compiled with MSVC 6.0.  The error was fixed in version 1.0.4e.
19  *
20  * [png_read_filter_row_mmx_avg() bpp == 2 bugfix, GRR 20000916]
21  *
22  * [runtime MMX configuration, GRR 20010102]
23  *
24  */
25
26 #define PNG_INTERNAL
27 #include "png.h"
28
29 #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_USE_PNGVCRD)
30
31 static int mmx_supported=2;
32
33
34 int PNGAPI
35 png_mmx_support(void)
36 {
37   int mmx_supported_local = 0;
38   _asm {
39     push ebx          //CPUID will trash these
40     push ecx
41     push edx
42
43     pushfd            //Save Eflag to stack
44     pop eax           //Get Eflag from stack into eax
45     mov ecx, eax      //Make another copy of Eflag in ecx
46     xor eax, 0x200000 //Toggle ID bit in Eflag [i.e. bit(21)]
47     push eax          //Save modified Eflag back to stack
48
49     popfd             //Restored modified value back to Eflag reg
50     pushfd            //Save Eflag to stack
51     pop eax           //Get Eflag from stack
52     push ecx          // save original Eflag to stack
53     popfd             // restore original Eflag
54     xor eax, ecx      //Compare the new Eflag with the original Eflag
55     jz NOT_SUPPORTED  //If the same, CPUID instruction is not supported,
56                       //skip following instructions and jump to
57                       //NOT_SUPPORTED label
58
59     xor eax, eax      //Set eax to zero
60
61     _asm _emit 0x0f   //CPUID instruction  (two bytes opcode)
62     _asm _emit 0xa2
63
64     cmp eax, 1        //make sure eax return non-zero value
65     jl NOT_SUPPORTED  //If eax is zero, mmx not supported
66
67     xor eax, eax      //set eax to zero
68     inc eax           //Now increment eax to 1.  This instruction is
69                       //faster than the instruction "mov eax, 1"
70
71     _asm _emit 0x0f   //CPUID instruction
72     _asm _emit 0xa2
73
74     and edx, 0x00800000  //mask out all bits but mmx bit(24)
75     cmp edx, 0        // 0 = mmx not supported
76     jz  NOT_SUPPORTED // non-zero = Yes, mmx IS supported
77
78     mov  mmx_supported_local, 1  //set return value to 1
79
80 NOT_SUPPORTED:
81     mov  eax, mmx_supported_local  //move return value to eax
82     pop edx          //CPUID trashed these
83     pop ecx
84     pop ebx
85   }
86
87   //mmx_supported_local=0; // test code for force don't support MMX
88   //printf("MMX : %u (1=MMX supported)\n",mmx_supported_local);
89
90   mmx_supported = mmx_supported_local;
91   return mmx_supported_local;
92 }
93
94 /* Combines the row recently read in with the previous row.
95    This routine takes care of alpha and transparency if requested.
96    This routine also handles the two methods of progressive display
97    of interlaced images, depending on the mask value.
98    The mask value describes which pixels are to be combined with
99    the row.  The pattern always repeats every 8 pixels, so just 8
100    bits are needed.  A one indicates the pixel is to be combined; a
101    zero indicates the pixel is to be skipped.  This is in addition
102    to any alpha or transparency value associated with the pixel.  If
103    you want all pixels to be combined, pass 0xff (255) in mask.  */
104
105 /* Use this routine for x86 platform - uses faster MMX routine if machine
106    supports MMX */
107
108 void /* PRIVATE */
109 png_combine_row(png_structp png_ptr, png_bytep row, int mask)
110 {
111 #ifdef PNG_USE_LOCAL_ARRAYS
112    const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
113 #endif
114
115    png_debug(1,"in png_combine_row_asm\n");
116
117    if (mmx_supported == 2) {
118 #if !defined(PNG_1_0_X)
119        /* this should have happened in png_init_mmx_flags() already */
120        png_warning(png_ptr, "asm_flags may not have been initialized");
121 #endif
122        png_mmx_support();
123    }
124
125    if (mask == 0xff)
126    {
127       png_memcpy(row, png_ptr->row_buf + 1,
128        (png_size_t)PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
129        png_ptr->width));
130    }
131    /* GRR:  add "else if (mask == 0)" case?
132     *       or does png_combine_row() not even get called in that case? */
133    else
134    {
135       switch (png_ptr->row_info.pixel_depth)
136       {
137          case 1:
138          {
139             png_bytep sp;
140             png_bytep dp;
141             int s_inc, s_start, s_end;
142             int m;
143             int shift;
144             png_uint_32 i;
145
146             sp = png_ptr->row_buf + 1;
147             dp = row;
148             m = 0x80;
149 #if defined(PNG_READ_PACKSWAP_SUPPORTED)
150             if (png_ptr->transformations & PNG_PACKSWAP)
151             {
152                 s_start = 0;
153                 s_end = 7;
154                 s_inc = 1;
155             }
156             else
157 #endif
158             {
159                 s_start = 7;
160                 s_end = 0;
161                 s_inc = -1;
162             }
163
164             shift = s_start;
165
166             for (i = 0; i < png_ptr->width; i++)
167             {
168                if (m & mask)
169                {
170                   int value;
171
172                   value = (*sp >> shift) & 0x1;
173                   *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
174                   *dp |= (png_byte)(value << shift);
175                }
176
177                if (shift == s_end)
178                {
179                   shift = s_start;
180                   sp++;
181                   dp++;
182                }
183                else
184                   shift += s_inc;
185
186                if (m == 1)
187                   m = 0x80;
188                else
189                   m >>= 1;
190             }
191             break;
192          }
193
194          case 2:
195          {
196             png_bytep sp;
197             png_bytep dp;
198             int s_start, s_end, s_inc;
199             int m;
200             int shift;
201             png_uint_32 i;
202             int value;
203
204             sp = png_ptr->row_buf + 1;
205             dp = row;
206             m = 0x80;
207 #if defined(PNG_READ_PACKSWAP_SUPPORTED)
208             if (png_ptr->transformations & PNG_PACKSWAP)
209             {
210                s_start = 0;
211                s_end = 6;
212                s_inc = 2;
213             }
214             else
215 #endif
216             {
217                s_start = 6;
218                s_end = 0;
219                s_inc = -2;
220             }
221
222             shift = s_start;
223
224             for (i = 0; i < png_ptr->width; i++)
225             {
226                if (m & mask)
227                {
228                   value = (*sp >> shift) & 0x3;
229                   *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
230                   *dp |= (png_byte)(value << shift);
231                }
232
233                if (shift == s_end)
234                {
235                   shift = s_start;
236                   sp++;
237                   dp++;
238                }
239                else
240                   shift += s_inc;
241                if (m == 1)
242                   m = 0x80;
243                else
244                   m >>= 1;
245             }
246             break;
247          }
248
249          case 4:
250          {
251             png_bytep sp;
252             png_bytep dp;
253             int s_start, s_end, s_inc;
254             int m;
255             int shift;
256             png_uint_32 i;
257             int value;
258
259             sp = png_ptr->row_buf + 1;
260             dp = row;
261             m = 0x80;
262 #if defined(PNG_READ_PACKSWAP_SUPPORTED)
263             if (png_ptr->transformations & PNG_PACKSWAP)
264             {
265                s_start = 0;
266                s_end = 4;
267                s_inc = 4;
268             }
269             else
270 #endif
271             {
272                s_start = 4;
273                s_end = 0;
274                s_inc = -4;
275             }
276             shift = s_start;
277
278             for (i = 0; i < png_ptr->width; i++)
279             {
280                if (m & mask)
281                {
282                   value = (*sp >> shift) & 0xf;
283                   *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
284                   *dp |= (png_byte)(value << shift);
285                }
286
287                if (shift == s_end)
288                {
289                   shift = s_start;
290                   sp++;
291                   dp++;
292                }
293                else
294                   shift += s_inc;
295                if (m == 1)
296                   m = 0x80;
297                else
298                   m >>= 1;
299             }
300             break;
301          }
302
303          case 8:
304          {
305             png_bytep srcptr;
306             png_bytep dstptr;
307             png_uint_32 len;
308             int m;
309             int diff, unmask;
310
311             __int64 mask0=0x0102040810204080;
312
313 #if !defined(PNG_1_0_X)
314             if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
315                 /* && mmx_supported */ )
316 #else
317             if (mmx_supported)
318 #endif
319             {
320                srcptr = png_ptr->row_buf + 1;
321                dstptr = row;
322                m = 0x80;
323                unmask = ~mask;
324                len  = png_ptr->width &~7;  //reduce to multiple of 8
325                diff = png_ptr->width & 7;  //amount lost
326
327                _asm
328                {
329                   movd       mm7, unmask   //load bit pattern
330                   psubb      mm6,mm6       //zero mm6
331                   punpcklbw  mm7,mm7
332                   punpcklwd  mm7,mm7
333                   punpckldq  mm7,mm7       //fill register with 8 masks
334
335                   movq       mm0,mask0
336
337                   pand       mm0,mm7       //nonzero if keep byte
338                   pcmpeqb    mm0,mm6       //zeros->1s, v versa
339
340                   mov        ecx,len       //load length of line (pixels)
341                   mov        esi,srcptr    //load source
342                   mov        ebx,dstptr    //load dest
343                   cmp        ecx,0         //lcr
344                   je         mainloop8end
345
346 mainloop8:
347                   movq       mm4,[esi]
348                   pand       mm4,mm0
349                   movq       mm6,mm0
350                   pandn      mm6,[ebx]
351                   por        mm4,mm6
352                   movq       [ebx],mm4
353
354                   add        esi,8         //inc by 8 bytes processed
355                   add        ebx,8
356                   sub        ecx,8         //dec by 8 pixels processed
357
358                   ja         mainloop8
359 mainloop8end:
360
361                   mov        ecx,diff
362                   cmp        ecx,0
363                   jz         end8
364
365                   mov        edx,mask
366                   sal        edx,24        //make low byte the high byte
367
368 secondloop8:
369                   sal        edx,1         //move high bit to CF
370                   jnc        skip8         //if CF = 0
371                   mov        al,[esi]
372                   mov        [ebx],al
373 skip8:
374                   inc        esi
375                   inc        ebx
376
377                   dec        ecx
378                   jnz        secondloop8
379 end8:
380                   emms
381                }
382             }
383             else /* mmx not supported - use modified C routine */
384             {
385                register unsigned int incr1, initial_val, final_val;
386                png_size_t pixel_bytes;
387                png_uint_32 i;
388                register int disp = png_pass_inc[png_ptr->pass];
389                int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
390
391                pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
392                srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
393                   pixel_bytes;
394                dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
395                initial_val = offset_table[png_ptr->pass]*pixel_bytes;
396                final_val = png_ptr->width*pixel_bytes;
397                incr1 = (disp)*pixel_bytes;
398                for (i = initial_val; i < final_val; i += incr1)
399                {
400                   png_memcpy(dstptr, srcptr, pixel_bytes);
401                   srcptr += incr1;
402                   dstptr += incr1;
403                }
404             } /* end of else */
405
406             break;
407          }       // end 8 bpp
408
409          case 16:
410          {
411             png_bytep srcptr;
412             png_bytep dstptr;
413             png_uint_32 len;
414             int unmask, diff;
415             __int64 mask1=0x0101020204040808,
416                     mask0=0x1010202040408080;
417
418 #if !defined(PNG_1_0_X)
419             if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
420                 /* && mmx_supported */ )
421 #else
422             if (mmx_supported)
423 #endif
424             {
425                srcptr = png_ptr->row_buf + 1;
426                dstptr = row;
427
428                unmask = ~mask;
429                len     = (png_ptr->width)&~7;
430                diff = (png_ptr->width)&7;
431                _asm
432                {
433                   movd       mm7, unmask       //load bit pattern
434                   psubb      mm6,mm6           //zero mm6
435                   punpcklbw  mm7,mm7
436                   punpcklwd  mm7,mm7
437                   punpckldq  mm7,mm7           //fill register with 8 masks
438
439                   movq       mm0,mask0
440                   movq       mm1,mask1
441
442                   pand       mm0,mm7
443                   pand       mm1,mm7
444
445                   pcmpeqb    mm0,mm6
446                   pcmpeqb    mm1,mm6
447
448                   mov        ecx,len           //load length of line
449                   mov        esi,srcptr        //load source
450                   mov        ebx,dstptr        //load dest
451                   cmp        ecx,0             //lcr
452                   jz         mainloop16end
453
454 mainloop16:
455                   movq       mm4,[esi]
456                   pand       mm4,mm0
457                   movq       mm6,mm0
458                   movq       mm7,[ebx]
459                   pandn      mm6,mm7
460                   por        mm4,mm6
461                   movq       [ebx],mm4
462
463                   movq       mm5,[esi+8]
464                   pand       mm5,mm1
465                   movq       mm7,mm1
466                   movq       mm6,[ebx+8]
467                   pandn      mm7,mm6
468                   por        mm5,mm7
469                   movq       [ebx+8],mm5
470
471                   add        esi,16            //inc by 16 bytes processed
472                   add        ebx,16
473                   sub        ecx,8             //dec by 8 pixels processed
474
475                   ja         mainloop16
476
477 mainloop16end:
478                   mov        ecx,diff
479                   cmp        ecx,0
480                   jz         end16
481
482                   mov        edx,mask
483                   sal        edx,24            //make low byte the high byte
484 secondloop16:
485                   sal        edx,1             //move high bit to CF
486                   jnc        skip16            //if CF = 0
487                   mov        ax,[esi]
488                   mov        [ebx],ax
489 skip16:
490                   add        esi,2
491                   add        ebx,2
492
493                   dec        ecx
494                   jnz        secondloop16
495 end16:
496                   emms
497                }
498             }
499             else /* mmx not supported - use modified C routine */
500             {
501                register unsigned int incr1, initial_val, final_val;
502                png_size_t pixel_bytes;
503                png_uint_32 i;
504                register int disp = png_pass_inc[png_ptr->pass];
505                int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
506
507                pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
508                srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
509                   pixel_bytes;
510                dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
511                initial_val = offset_table[png_ptr->pass]*pixel_bytes;
512                final_val = png_ptr->width*pixel_bytes;
513                incr1 = (disp)*pixel_bytes;
514                for (i = initial_val; i < final_val; i += incr1)
515                {
516                   png_memcpy(dstptr, srcptr, pixel_bytes);
517                   srcptr += incr1;
518                   dstptr += incr1;
519                }
520             } /* end of else */
521
522             break;
523          }       // end 16 bpp
524
525          case 24:
526          {
527             png_bytep srcptr;
528             png_bytep dstptr;
529             png_uint_32 len;
530             int unmask, diff;
531
532             __int64 mask2=0x0101010202020404,  //24bpp
533                     mask1=0x0408080810101020,
534                     mask0=0x2020404040808080;
535
536             srcptr = png_ptr->row_buf + 1;
537             dstptr = row;
538
539             unmask = ~mask;
540             len     = (png_ptr->width)&~7;
541             diff = (png_ptr->width)&7;
542
543 #if !defined(PNG_1_0_X)
544             if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
545                 /* && mmx_supported */ )
546 #else
547             if (mmx_supported)
548 #endif
549             {
550                _asm
551                {
552                   movd       mm7, unmask       //load bit pattern
553                   psubb      mm6,mm6           //zero mm6
554                   punpcklbw  mm7,mm7
555                   punpcklwd  mm7,mm7
556                   punpckldq  mm7,mm7           //fill register with 8 masks
557
558                   movq       mm0,mask0
559                   movq       mm1,mask1
560                   movq       mm2,mask2
561
562                   pand       mm0,mm7
563                   pand       mm1,mm7
564                   pand       mm2,mm7
565
566                   pcmpeqb    mm0,mm6
567                   pcmpeqb    mm1,mm6
568                   pcmpeqb    mm2,mm6
569
570                   mov        ecx,len           //load length of line
571                   mov        esi,srcptr        //load source
572                   mov        ebx,dstptr        //load dest
573                   cmp        ecx,0
574                   jz         mainloop24end
575
576 mainloop24:
577                   movq       mm4,[esi]
578                   pand       mm4,mm0
579                   movq       mm6,mm0
580                   movq       mm7,[ebx]
581                   pandn      mm6,mm7
582                   por        mm4,mm6
583                   movq       [ebx],mm4
584
585
586                   movq       mm5,[esi+8]
587                   pand       mm5,mm1
588                   movq       mm7,mm1
589                   movq       mm6,[ebx+8]
590                   pandn      mm7,mm6
591                   por        mm5,mm7
592                   movq       [ebx+8],mm5
593
594                   movq       mm6,[esi+16]
595                   pand       mm6,mm2
596                   movq       mm4,mm2
597                   movq       mm7,[ebx+16]
598                   pandn      mm4,mm7
599                   por        mm6,mm4
600                   movq       [ebx+16],mm6
601
602                   add        esi,24            //inc by 24 bytes processed
603                   add        ebx,24
604                   sub        ecx,8             //dec by 8 pixels processed
605
606                   ja         mainloop24
607
608 mainloop24end:
609                   mov        ecx,diff
610                   cmp        ecx,0
611                   jz         end24
612
613                   mov        edx,mask
614                   sal        edx,24            //make low byte the high byte
615 secondloop24:
616                   sal        edx,1             //move high bit to CF
617                   jnc        skip24            //if CF = 0
618                   mov        ax,[esi]
619                   mov        [ebx],ax
620                   xor        eax,eax
621                   mov        al,[esi+2]
622                   mov        [ebx+2],al
623 skip24:
624                   add        esi,3
625                   add        ebx,3
626
627                   dec        ecx
628                   jnz        secondloop24
629
630 end24:
631                   emms
632                }
633             }
634             else /* mmx not supported - use modified C routine */
635             {
636                register unsigned int incr1, initial_val, final_val;
637                png_size_t pixel_bytes;
638                png_uint_32 i;
639                register int disp = png_pass_inc[png_ptr->pass];
640                int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
641
642                pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
643                srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
644                   pixel_bytes;
645                dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
646                initial_val = offset_table[png_ptr->pass]*pixel_bytes;
647                final_val = png_ptr->width*pixel_bytes;
648                incr1 = (disp)*pixel_bytes;
649                for (i = initial_val; i < final_val; i += incr1)
650                {
651                   png_memcpy(dstptr, srcptr, pixel_bytes);
652                   srcptr += incr1;
653                   dstptr += incr1;
654                }
655             } /* end of else */
656
657             break;
658          }       // end 24 bpp
659
660          case 32:
661          {
662             png_bytep srcptr;
663             png_bytep dstptr;
664             png_uint_32 len;
665             int unmask, diff;
666
667             __int64 mask3=0x0101010102020202,  //32bpp
668                     mask2=0x0404040408080808,
669                     mask1=0x1010101020202020,
670                     mask0=0x4040404080808080;
671
672             srcptr = png_ptr->row_buf + 1;
673             dstptr = row;
674
675             unmask = ~mask;
676             len     = (png_ptr->width)&~7;
677             diff = (png_ptr->width)&7;
678
679 #if !defined(PNG_1_0_X)
680             if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
681                 /* && mmx_supported */ )
682 #else
683             if (mmx_supported)
684 #endif
685             {
686                _asm
687                {
688                   movd       mm7, unmask       //load bit pattern
689                   psubb      mm6,mm6           //zero mm6
690                   punpcklbw  mm7,mm7
691                   punpcklwd  mm7,mm7
692                   punpckldq  mm7,mm7           //fill register with 8 masks
693
694                   movq       mm0,mask0
695                   movq       mm1,mask1
696                   movq       mm2,mask2
697                   movq       mm3,mask3
698
699                   pand       mm0,mm7
700                   pand       mm1,mm7
701                   pand       mm2,mm7
702                   pand       mm3,mm7
703
704                   pcmpeqb    mm0,mm6
705                   pcmpeqb    mm1,mm6
706                   pcmpeqb    mm2,mm6
707                   pcmpeqb    mm3,mm6
708
709                   mov        ecx,len           //load length of line
710                   mov        esi,srcptr        //load source
711                   mov        ebx,dstptr        //load dest
712
713                   cmp        ecx,0             //lcr
714                   jz         mainloop32end
715
716 mainloop32:
717                   movq       mm4,[esi]
718                   pand       mm4,mm0
719                   movq       mm6,mm0
720                   movq       mm7,[ebx]
721                   pandn      mm6,mm7
722                   por        mm4,mm6
723                   movq       [ebx],mm4
724
725                   movq       mm5,[esi+8]
726                   pand       mm5,mm1
727                   movq       mm7,mm1
728                   movq       mm6,[ebx+8]
729                   pandn      mm7,mm6
730                   por        mm5,mm7
731                   movq       [ebx+8],mm5
732
733                   movq       mm6,[esi+16]
734                   pand       mm6,mm2
735                   movq       mm4,mm2
736                   movq       mm7,[ebx+16]
737                   pandn      mm4,mm7
738                   por        mm6,mm4
739                   movq       [ebx+16],mm6
740
741                   movq       mm7,[esi+24]
742                   pand       mm7,mm3
743                   movq       mm5,mm3
744                   movq       mm4,[ebx+24]
745                   pandn      mm5,mm4
746                   por        mm7,mm5
747                   movq       [ebx+24],mm7
748
749                   add        esi,32            //inc by 32 bytes processed
750                   add        ebx,32
751                   sub        ecx,8             //dec by 8 pixels processed
752
753                   ja         mainloop32
754
755 mainloop32end:
756                   mov        ecx,diff
757                   cmp        ecx,0
758                   jz         end32
759
760                   mov        edx,mask
761                   sal        edx,24            //make low byte the high byte
762 secondloop32:
763                   sal        edx,1             //move high bit to CF
764                   jnc        skip32            //if CF = 0
765                   mov        eax,[esi]
766                   mov        [ebx],eax
767 skip32:
768                   add        esi,4
769                   add        ebx,4
770
771                   dec        ecx
772                   jnz        secondloop32
773
774 end32:
775                   emms
776                }
777             }
778             else /* mmx _not supported - Use modified C routine */
779             {
780                register unsigned int incr1, initial_val, final_val;
781                png_size_t pixel_bytes;
782                png_uint_32 i;
783                register int disp = png_pass_inc[png_ptr->pass];
784                int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
785
786                pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
787                srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
788                   pixel_bytes;
789                dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
790                initial_val = offset_table[png_ptr->pass]*pixel_bytes;
791                final_val = png_ptr->width*pixel_bytes;
792                incr1 = (disp)*pixel_bytes;
793                for (i = initial_val; i < final_val; i += incr1)
794                {
795                   png_memcpy(dstptr, srcptr, pixel_bytes);
796                   srcptr += incr1;
797                   dstptr += incr1;
798                }
799             } /* end of else */
800
801             break;
802          }       // end 32 bpp
803
804          case 48:
805          {
806             png_bytep srcptr;
807             png_bytep dstptr;
808             png_uint_32 len;
809             int unmask, diff;
810
811             __int64 mask5=0x0101010101010202,
812                     mask4=0x0202020204040404,
813                     mask3=0x0404080808080808,
814                     mask2=0x1010101010102020,
815                     mask1=0x2020202040404040,
816                     mask0=0x4040808080808080;
817
818 #if !defined(PNG_1_0_X)
819             if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
820                 /* && mmx_supported */ )
821 #else
822             if (mmx_supported)
823 #endif
824             {
825                srcptr = png_ptr->row_buf + 1;
826                dstptr = row;
827
828                unmask = ~mask;
829                len     = (png_ptr->width)&~7;
830                diff = (png_ptr->width)&7;
831                _asm
832                {
833                   movd       mm7, unmask       //load bit pattern
834                   psubb      mm6,mm6           //zero mm6
835                   punpcklbw  mm7,mm7
836                   punpcklwd  mm7,mm7
837                   punpckldq  mm7,mm7           //fill register with 8 masks
838
839                   movq       mm0,mask0
840                   movq       mm1,mask1
841                   movq       mm2,mask2
842                   movq       mm3,mask3
843                   movq       mm4,mask4
844                   movq       mm5,mask5
845
846                   pand       mm0,mm7
847                   pand       mm1,mm7
848                   pand       mm2,mm7
849                   pand       mm3,mm7
850                   pand       mm4,mm7
851                   pand       mm5,mm7
852
853                   pcmpeqb    mm0,mm6
854                   pcmpeqb    mm1,mm6
855                   pcmpeqb    mm2,mm6
856                   pcmpeqb    mm3,mm6
857                   pcmpeqb    mm4,mm6
858                   pcmpeqb    mm5,mm6
859
860                   mov        ecx,len           //load length of line
861                   mov        esi,srcptr        //load source
862                   mov        ebx,dstptr        //load dest
863
864                   cmp        ecx,0
865                   jz         mainloop48end
866
867 mainloop48:
868                   movq       mm7,[esi]
869                   pand       mm7,mm0
870                   movq       mm6,mm0
871                   pandn      mm6,[ebx]
872                   por        mm7,mm6
873                   movq       [ebx],mm7
874
875                   movq       mm6,[esi+8]
876                   pand       mm6,mm1
877                   movq       mm7,mm1
878                   pandn      mm7,[ebx+8]
879                   por        mm6,mm7
880                   movq       [ebx+8],mm6
881
882                   movq       mm6,[esi+16]
883                   pand       mm6,mm2
884                   movq       mm7,mm2
885                   pandn      mm7,[ebx+16]
886                   por        mm6,mm7
887                   movq       [ebx+16],mm6
888
889                   movq       mm7,[esi+24]
890                   pand       mm7,mm3
891                   movq       mm6,mm3
892                   pandn      mm6,[ebx+24]
893                   por        mm7,mm6
894                   movq       [ebx+24],mm7
895
896                   movq       mm6,[esi+32]
897                   pand       mm6,mm4
898                   movq       mm7,mm4
899                   pandn      mm7,[ebx+32]
900                   por        mm6,mm7
901                   movq       [ebx+32],mm6
902
903                   movq       mm7,[esi+40]
904                   pand       mm7,mm5
905                   movq       mm6,mm5
906                   pandn      mm6,[ebx+40]
907                   por        mm7,mm6
908                   movq       [ebx+40],mm7
909
910                   add        esi,48            //inc by 32 bytes processed
911                   add        ebx,48
912                   sub        ecx,8             //dec by 8 pixels processed
913
914                   ja         mainloop48
915 mainloop48end:
916
917                   mov        ecx,diff
918                   cmp        ecx,0
919                   jz         end48
920
921                   mov        edx,mask
922                   sal        edx,24            //make low byte the high byte
923
924 secondloop48:
925                   sal        edx,1             //move high bit to CF
926                   jnc        skip48            //if CF = 0
927                   mov        eax,[esi]
928                   mov        [ebx],eax
929 skip48:
930                   add        esi,4
931                   add        ebx,4
932
933                   dec        ecx
934                   jnz        secondloop48
935
936 end48:
937                   emms
938                }
939             }
940             else /* mmx _not supported - Use modified C routine */
941             {
942                register unsigned int incr1, initial_val, final_val;
943                png_size_t pixel_bytes;
944                png_uint_32 i;
945                register int disp = png_pass_inc[png_ptr->pass];
946                int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
947
948                pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
949                srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
950                   pixel_bytes;
951                dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
952                initial_val = offset_table[png_ptr->pass]*pixel_bytes;
953                final_val = png_ptr->width*pixel_bytes;
954                incr1 = (disp)*pixel_bytes;
955                for (i = initial_val; i < final_val; i += incr1)
956                {
957                   png_memcpy(dstptr, srcptr, pixel_bytes);
958                   srcptr += incr1;
959                   dstptr += incr1;
960                }
961             } /* end of else */
962
963             break;
964          }       // end 48 bpp
965
966          default:
967          {
968             png_bytep sptr;
969             png_bytep dp;
970             png_size_t pixel_bytes;
971             int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
972             unsigned int i;
973             register int disp = png_pass_inc[png_ptr->pass];  // get the offset
974             register unsigned int incr1, initial_val, final_val;
975
976             pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
977             sptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
978                pixel_bytes;
979             dp = row + offset_table[png_ptr->pass]*pixel_bytes;
980             initial_val = offset_table[png_ptr->pass]*pixel_bytes;
981             final_val = png_ptr->width*pixel_bytes;
982             incr1 = (disp)*pixel_bytes;
983             for (i = initial_val; i < final_val; i += incr1)
984             {
985                png_memcpy(dp, sptr, pixel_bytes);
986                sptr += incr1;
987                dp += incr1;
988             }
989             break;
990          }
991       } /* end switch (png_ptr->row_info.pixel_depth) */
992    } /* end if (non-trivial mask) */
993
994 } /* end png_combine_row() */
995
996
997 #if defined(PNG_READ_INTERLACING_SUPPORTED)
998
999 void /* PRIVATE */
1000 png_do_read_interlace(png_structp png_ptr)
1001 {
1002    png_row_infop row_info = &(png_ptr->row_info);
1003    png_bytep row = png_ptr->row_buf + 1;
1004    int pass = png_ptr->pass;
1005    png_uint_32 transformations = png_ptr->transformations;
1006 #ifdef PNG_USE_LOCAL_ARRAYS
1007    const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
1008 #endif
1009
1010    png_debug(1,"in png_do_read_interlace\n");
1011
1012    if (mmx_supported == 2) {
1013 #if !defined(PNG_1_0_X)
1014        /* this should have happened in png_init_mmx_flags() already */
1015        png_warning(png_ptr, "asm_flags may not have been initialized");
1016 #endif
1017        png_mmx_support();
1018    }
1019
1020    if (row != NULL && row_info != NULL)
1021    {
1022       png_uint_32 final_width;
1023
1024       final_width = row_info->width * png_pass_inc[pass];
1025
1026       switch (row_info->pixel_depth)
1027       {
1028          case 1:
1029          {
1030             png_bytep sp, dp;
1031             int sshift, dshift;
1032             int s_start, s_end, s_inc;
1033             png_byte v;
1034             png_uint_32 i;
1035             int j;
1036
1037             sp = row + (png_size_t)((row_info->width - 1) >> 3);
1038             dp = row + (png_size_t)((final_width - 1) >> 3);
1039 #if defined(PNG_READ_PACKSWAP_SUPPORTED)
1040             if (transformations & PNG_PACKSWAP)
1041             {
1042                sshift = (int)((row_info->width + 7) & 7);
1043                dshift = (int)((final_width + 7) & 7);
1044                s_start = 7;
1045                s_end = 0;
1046                s_inc = -1;
1047             }
1048             else
1049 #endif
1050             {
1051                sshift = 7 - (int)((row_info->width + 7) & 7);
1052                dshift = 7 - (int)((final_width + 7) & 7);
1053                s_start = 0;
1054                s_end = 7;
1055                s_inc = 1;
1056             }
1057
1058             for (i = row_info->width; i; i--)
1059             {
1060                v = (png_byte)((*sp >> sshift) & 0x1);
1061                for (j = 0; j < png_pass_inc[pass]; j++)
1062                {
1063                   *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
1064                   *dp |= (png_byte)(v << dshift);
1065                   if (dshift == s_end)
1066                   {
1067                      dshift = s_start;
1068                      dp--;
1069                   }
1070                   else
1071                      dshift += s_inc;
1072                }
1073                if (sshift == s_end)
1074                {
1075                   sshift = s_start;
1076                   sp--;
1077                }
1078                else
1079                   sshift += s_inc;
1080             }
1081             break;
1082          }
1083
1084          case 2:
1085          {
1086             png_bytep sp, dp;
1087             int sshift, dshift;
1088             int s_start, s_end, s_inc;
1089             png_uint_32 i;
1090
1091             sp = row + (png_size_t)((row_info->width - 1) >> 2);
1092             dp = row + (png_size_t)((final_width - 1) >> 2);
1093 #if defined(PNG_READ_PACKSWAP_SUPPORTED)
1094             if (transformations & PNG_PACKSWAP)
1095             {
1096                sshift = (png_size_t)(((row_info->width + 3) & 3) << 1);
1097                dshift = (png_size_t)(((final_width + 3) & 3) << 1);
1098                s_start = 6;
1099                s_end = 0;
1100                s_inc = -2;
1101             }
1102             else
1103 #endif
1104             {
1105                sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
1106                dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
1107                s_start = 0;
1108                s_end = 6;
1109                s_inc = 2;
1110             }
1111
1112             for (i = row_info->width; i; i--)
1113             {
1114                png_byte v;
1115                int j;
1116
1117                v = (png_byte)((*sp >> sshift) & 0x3);
1118                for (j = 0; j < png_pass_inc[pass]; j++)
1119                {
1120                   *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
1121                   *dp |= (png_byte)(v << dshift);
1122                   if (dshift == s_end)
1123                   {
1124                      dshift = s_start;
1125                      dp--;
1126                   }
1127                   else
1128                      dshift += s_inc;
1129                }
1130                if (sshift == s_end)
1131                {
1132                   sshift = s_start;
1133                   sp--;
1134                }
1135                else
1136                   sshift += s_inc;
1137             }
1138             break;
1139          }
1140
1141          case 4:
1142          {
1143             png_bytep sp, dp;
1144             int sshift, dshift;
1145             int s_start, s_end, s_inc;
1146             png_uint_32 i;
1147
1148             sp = row + (png_size_t)((row_info->width - 1) >> 1);
1149             dp = row + (png_size_t)((final_width - 1) >> 1);
1150 #if defined(PNG_READ_PACKSWAP_SUPPORTED)
1151             if (transformations & PNG_PACKSWAP)
1152             {
1153                sshift = (png_size_t)(((row_info->width + 1) & 1) << 2);
1154                dshift = (png_size_t)(((final_width + 1) & 1) << 2);
1155                s_start = 4;
1156                s_end = 0;
1157                s_inc = -4;
1158             }
1159             else
1160 #endif
1161             {
1162                sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
1163                dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
1164                s_start = 0;
1165                s_end = 4;
1166                s_inc = 4;
1167             }
1168
1169             for (i = row_info->width; i; i--)
1170             {
1171                png_byte v;
1172                int j;
1173
1174                v = (png_byte)((*sp >> sshift) & 0xf);
1175                for (j = 0; j < png_pass_inc[pass]; j++)
1176                {
1177                   *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
1178                   *dp |= (png_byte)(v << dshift);
1179                   if (dshift == s_end)
1180                   {
1181                      dshift = s_start;
1182                      dp--;
1183                   }
1184                   else
1185                      dshift += s_inc;
1186                }
1187                if (sshift == s_end)
1188                {
1189                   sshift = s_start;
1190                   sp--;
1191                }
1192                else
1193                   sshift += s_inc;
1194             }
1195             break;
1196          }
1197
1198          default:         // This is the place where the routine is modified
1199          {
1200             __int64 const4 = 0x0000000000FFFFFF;
1201             // __int64 const5 = 0x000000FFFFFF0000;  // unused...
1202             __int64 const6 = 0x00000000000000FF;
1203             png_bytep sptr, dp;
1204             png_uint_32 i;
1205             png_size_t pixel_bytes;
1206             int width = row_info->width;
1207
1208             pixel_bytes = (row_info->pixel_depth >> 3);
1209
1210             sptr = row + (width - 1) * pixel_bytes;
1211             dp = row + (final_width - 1) * pixel_bytes;
1212             // New code by Nirav Chhatrapati - Intel Corporation
1213             // sign fix by GRR
1214             // NOTE:  there is NO MMX code for 48-bit and 64-bit images
1215
1216             // use MMX routine if machine supports it
1217 #if !defined(PNG_1_0_X)
1218             if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE)
1219                 /* && mmx_supported */ )
1220 #else
1221             if (mmx_supported)
1222 #endif
1223             {
1224                if (pixel_bytes == 3)
1225                {
1226                   if (((pass == 0) || (pass == 1)) && width)
1227                   {
1228                      _asm
1229                      {
1230                         mov esi, sptr
1231                         mov edi, dp
1232                         mov ecx, width
1233                         sub edi, 21   // (png_pass_inc[pass] - 1)*pixel_bytes
1234 loop_pass0:
1235                         movd mm0, [esi]     ; X X X X X v2 v1 v0
1236                         pand mm0, const4    ; 0 0 0 0 0 v2 v1 v0
1237                         movq mm1, mm0       ; 0 0 0 0 0 v2 v1 v0
1238                         psllq mm0, 16       ; 0 0 0 v2 v1 v0 0 0
1239                         movq mm2, mm0       ; 0 0 0 v2 v1 v0 0 0
1240                         psllq mm0, 24       ; v2 v1 v0 0 0 0 0 0
1241                         psrlq mm1, 8        ; 0 0 0 0 0 0 v2 v1
1242                         por mm0, mm2        ; v2 v1 v0 v2 v1 v0 0 0
1243                         por mm0, mm1        ; v2 v1 v0 v2 v1 v0 v2 v1
1244                         movq mm3, mm0       ; v2 v1 v0 v2 v1 v0 v2 v1
1245                         psllq mm0, 16       ; v0 v2 v1 v0 v2 v1 0 0
1246                         movq mm4, mm3       ; v2 v1 v0 v2 v1 v0 v2 v1
1247                         punpckhdq mm3, mm0  ; v0 v2 v1 v0 v2 v1 v0 v2
1248                         movq [edi+16] , mm4
1249                         psrlq mm0, 32       ; 0 0 0 0 v0 v2 v1 v0
1250                         movq [edi+8] , mm3
1251                         punpckldq mm0, mm4  ; v1 v0 v2 v1 v0 v2 v1 v0
1252                         sub esi, 3
1253                         movq [edi], mm0
1254                         sub edi, 24
1255                         //sub esi, 3
1256                         dec ecx
1257                         jnz loop_pass0
1258                         EMMS
1259                      }
1260                   }
1261                   else if (((pass == 2) || (pass == 3)) && width)
1262                   {
1263                      _asm
1264                      {
1265                         mov esi, sptr
1266                         mov edi, dp
1267                         mov ecx, width
1268                         sub edi, 9   // (png_pass_inc[pass] - 1)*pixel_bytes
1269 loop_pass2:
1270                         movd mm0, [esi]     ; X X X X X v2 v1 v0
1271                         pand mm0, const4    ; 0 0 0 0 0 v2 v1 v0
1272                         movq mm1, mm0       ; 0 0 0 0 0 v2 v1 v0
1273                         psllq mm0, 16       ; 0 0 0 v2 v1 v0 0 0
1274                         movq mm2, mm0       ; 0 0 0 v2 v1 v0 0 0
1275                         psllq mm0, 24       ; v2 v1 v0 0 0 0 0 0
1276                         psrlq mm1, 8        ; 0 0 0 0 0 0 v2 v1
1277                         por mm0, mm2        ; v2 v1 v0 v2 v1 v0 0 0
1278                         por mm0, mm1        ; v2 v1 v0 v2 v1 v0 v2 v1
1279                         movq [edi+4], mm0   ; move to memory
1280                         psrlq mm0, 16       ; 0 0 v2 v1 v0 v2 v1 v0
1281                         movd [edi], mm0     ; move to memory
1282                         sub esi, 3
1283                         sub edi, 12
1284                         dec ecx
1285                         jnz loop_pass2
1286                         EMMS
1287                      }
1288                   }
1289                   else if (width) /* && ((pass == 4) || (pass == 5)) */
1290                   {
1291                      int width_mmx = ((width >> 1) << 1) - 8;
1292                      if (width_mmx < 0)
1293                          width_mmx = 0;
1294                      width -= width_mmx;        // 8 or 9 pix, 24 or 27 bytes
1295                      if (width_mmx)
1296                      {
1297                         _asm
1298                         {
1299                            mov esi, sptr
1300                            mov edi, dp
1301                            mov ecx, width_mmx
1302                            sub esi, 3
1303                            sub edi, 9
1304 loop_pass4:
1305                            movq mm0, [esi]     ; X X v2 v1 v0 v5 v4 v3
1306                            movq mm7, mm0       ; X X v2 v1 v0 v5 v4 v3
1307                            movq mm6, mm0       ; X X v2 v1 v0 v5 v4 v3
1308                            psllq mm0, 24       ; v1 v0 v5 v4 v3 0 0 0
1309                            pand mm7, const4    ; 0 0 0 0 0 v5 v4 v3
1310                            psrlq mm6, 24       ; 0 0 0 X X v2 v1 v0
1311                            por mm0, mm7        ; v1 v0 v5 v4 v3 v5 v4 v3
1312                            movq mm5, mm6       ; 0 0 0 X X v2 v1 v0
1313                            psllq mm6, 8        ; 0 0 X X v2 v1 v0 0
1314                            movq [edi], mm0     ; move quad to memory
1315                            psrlq mm5, 16       ; 0 0 0 0 0 X X v2
1316                            pand mm5, const6    ; 0 0 0 0 0 0 0 v2
1317                            por mm6, mm5        ; 0 0 X X v2 v1 v0 v2
1318                            movd [edi+8], mm6   ; move double to memory
1319                            sub esi, 6
1320                            sub edi, 12
1321                            sub ecx, 2
1322                            jnz loop_pass4
1323                            EMMS
1324                         }
1325                      }
1326
1327                      sptr -= width_mmx*3;
1328                      dp -= width_mmx*6;
1329                      for (i = width; i; i--)
1330                      {
1331                         png_byte v[8];
1332                         int j;
1333
1334                         png_memcpy(v, sptr, 3);
1335                         for (j = 0; j < png_pass_inc[pass]; j++)
1336                         {
1337                            png_memcpy(dp, v, 3);
1338                            dp -= 3;
1339                         }
1340                         sptr -= 3;
1341                      }
1342                   }
1343                } /* end of pixel_bytes == 3 */
1344
1345                else if (pixel_bytes == 1)
1346                {
1347                   if (((pass == 0) || (pass == 1)) && width)
1348                   {
1349                      int width_mmx = ((width >> 2) << 2);
1350                      width -= width_mmx;
1351                      if (width_mmx)
1352                      {
1353                         _asm
1354                         {
1355                            mov esi, sptr
1356                            mov edi, dp
1357                            mov ecx, width_mmx
1358                            sub edi, 31
1359                            sub esi, 3
1360 loop1_pass0:
1361                            movd mm0, [esi]     ; X X X X v0 v1 v2 v3
1362                            movq mm1, mm0       ; X X X X v0 v1 v2 v3
1363                            punpcklbw mm0, mm0  ; v0 v0 v1 v1 v2 v2 v3 v3
1364                            movq mm2, mm0       ; v0 v0 v1 v1 v2 v2 v3 v3
1365                            punpcklwd mm0, mm0  ; v2 v2 v2 v2 v3 v3 v3 v3
1366                            movq mm3, mm0       ; v2 v2 v2 v2 v3 v3 v3 v3
1367                            punpckldq mm0, mm0  ; v3 v3 v3 v3 v3 v3 v3 v3
1368                            punpckhdq mm3, mm3  ; v2 v2 v2 v2 v2 v2 v2 v2
1369                            movq [edi], mm0     ; move to memory v3
1370                            punpckhwd mm2, mm2  ; v0 v0 v0 v0 v1 v1 v1 v1
1371                            movq [edi+8], mm3   ; move to memory v2
1372                            movq mm4, mm2       ; v0 v0 v0 v0 v1 v1 v1 v1
1373                            punpckldq mm2, mm2  ; v1 v1 v1 v1 v1 v1 v1 v1
1374                            punpckhdq mm4, mm4  ; v0 v0 v0 v0 v0 v0 v0 v0
1375                            movq [edi+16], mm2  ; move to memory v1
1376                            movq [edi+24], mm4  ; move to memory v0
1377                            sub esi, 4
1378                            sub edi, 32
1379                            sub ecx, 4
1380                            jnz loop1_pass0
1381                            EMMS
1382                         }
1383                      }
1384
1385                      sptr -= width_mmx;
1386                      dp -= width_mmx*8;
1387                      for (i = width; i; i--)
1388                      {
1389                         int j;
1390
1391                        /* I simplified this part in version 1.0.4e
1392                         * here and in several other instances where
1393                         * pixel_bytes == 1  -- GR-P
1394                         *
1395                         * Original code:
1396                         *
1397                         * png_byte v[8];
1398                         * png_memcpy(v, sptr, pixel_bytes);
1399                         * for (j = 0; j < png_pass_inc[pass]; j++)
1400                         * {
1401                         *    png_memcpy(dp, v, pixel_bytes);
1402                         *    dp -= pixel_bytes;
1403                         * }
1404                         * sptr -= pixel_bytes;
1405                         *
1406                         * Replacement code is in the next three lines:
1407                         */
1408
1409                         for (j = 0; j < png_pass_inc[pass]; j++)
1410                            *dp-- = *sptr;
1411                         sptr--;
1412                      }
1413                   }
1414                   else if (((pass == 2) || (pass == 3)) && width)
1415                   {
1416                      int width_mmx = ((width >> 2) << 2);
1417                      width -= width_mmx;
1418                      if (width_mmx)
1419                      {
1420                         _asm
1421                         {
1422                            mov esi, sptr
1423                            mov edi, dp
1424                            mov ecx, width_mmx
1425                            sub edi, 15
1426                            sub esi, 3
1427 loop1_pass2:
1428                            movd mm0, [esi]     ; X X X X v0 v1 v2 v3
1429                            punpcklbw mm0, mm0  ; v0 v0 v1 v1 v2 v2 v3 v3
1430                            movq mm1, mm0       ; v0 v0 v1 v1 v2 v2 v3 v3
1431                            punpcklwd mm0, mm0  ; v2 v2 v2 v2 v3 v3 v3 v3
1432                            punpckhwd mm1, mm1  ; v0 v0 v0 v0 v1 v1 v1 v1
1433                            movq [edi], mm0     ; move to memory v2 and v3
1434                            sub esi, 4
1435                            movq [edi+8], mm1   ; move to memory v1     and v0
1436                            sub edi, 16
1437                            sub ecx, 4
1438                            jnz loop1_pass2
1439                            EMMS
1440                         }
1441                      }
1442
1443                      sptr -= width_mmx;
1444                      dp -= width_mmx*4;
1445                      for (i = width; i; i--)
1446                      {
1447                         int j;
1448
1449                         for (j = 0; j < png_pass_inc[pass]; j++)
1450                         {
1451                            *dp-- = *sptr;
1452                         }
1453                         sptr --;
1454                      }
1455                   }
1456                   else if (width) /* && ((pass == 4) || (pass == 5))) */
1457                   {
1458                      int width_mmx = ((width >> 3) << 3);
1459                      width -= width_mmx;
1460                      if (width_mmx)
1461                      {
1462                         _asm
1463                         {
1464                            mov esi, sptr
1465                            mov edi, dp
1466                            mov ecx, width_mmx
1467                            sub edi, 15
1468                            sub esi, 7
1469 loop1_pass4:
1470                            movq mm0, [esi]     ; v0 v1 v2 v3 v4 v5 v6 v7
1471                            movq mm1, mm0       ; v0 v1 v2 v3 v4 v5 v6 v7
1472                            punpcklbw mm0, mm0  ; v4 v4 v5 v5 v6 v6 v7 v7
1473                            //movq mm1, mm0     ; v0 v0 v1 v1 v2 v2 v3 v3
1474                            punpckhbw mm1, mm1  ;v0 v0 v1 v1 v2 v2 v3 v3
1475                            movq [edi+8], mm1   ; move to memory v0 v1 v2 and v3
1476                            sub esi, 8
1477                            movq [edi], mm0     ; move to memory v4 v5 v6 and v7
1478                            //sub esi, 4
1479                            sub edi, 16
1480                            sub ecx, 8
1481                            jnz loop1_pass4
1482                            EMMS
1483                         }
1484                      }
1485
1486                      sptr -= width_mmx;
1487                      dp -= width_mmx*2;
1488                      for (i = width; i; i--)
1489                      {
1490                         int j;
1491
1492                         for (j = 0; j < png_pass_inc[pass]; j++)
1493                         {
1494                            *dp-- = *sptr;
1495                         }
1496                         sptr --;
1497                      }
1498                   }
1499                } /* end of pixel_bytes == 1 */
1500
1501                else if (pixel_bytes == 2)
1502                {
1503                   if (((pass == 0) || (pass == 1)) && width)
1504                   {
1505                      int width_mmx = ((width >> 1) << 1);
1506                      width -= width_mmx;
1507                      if (width_mmx)
1508                      {
1509                         _asm
1510                         {
1511                            mov esi, sptr
1512                            mov edi, dp
1513                            mov ecx, width_mmx
1514                            sub esi, 2
1515                            sub edi, 30
1516 loop2_pass0:
1517                            movd mm0, [esi]        ; X X X X v1 v0 v3 v2
1518                            punpcklwd mm0, mm0     ; v1 v0 v1 v0 v3 v2 v3 v2
1519                            movq mm1, mm0          ; v1 v0 v1 v0 v3 v2 v3 v2
1520                            punpckldq mm0, mm0     ; v3 v2 v3 v2 v3 v2 v3 v2
1521                            punpckhdq mm1, mm1     ; v1 v0 v1 v0 v1 v0 v1 v0
1522                            movq [edi], mm0
1523                            movq [edi + 8], mm0
1524                            movq [edi + 16], mm1
1525                            movq [edi + 24], mm1
1526                            sub esi, 4
1527                            sub edi, 32
1528                            sub ecx, 2
1529                            jnz loop2_pass0
1530                            EMMS
1531                         }
1532                      }
1533
1534                      sptr -= (width_mmx*2 - 2);            // sign fixed
1535                      dp -= (width_mmx*16 - 2);            // sign fixed
1536                      for (i = width; i; i--)
1537                      {
1538                         png_byte v[8];
1539                         int j;
1540                         sptr -= 2;
1541                         png_memcpy(v, sptr, 2);
1542                         for (j = 0; j < png_pass_inc[pass]; j++)
1543                         {
1544                            dp -= 2;
1545                            png_memcpy(dp, v, 2);
1546                         }
1547                      }
1548                   }
1549                   else if (((pass == 2) || (pass == 3)) && width)
1550                   {
1551                      int width_mmx = ((width >> 1) << 1) ;
1552                      width -= width_mmx;
1553                      if (width_mmx)
1554                      {
1555                         _asm
1556                         {
1557                            mov esi, sptr
1558                            mov edi, dp
1559                            mov ecx, width_mmx
1560                            sub esi, 2
1561                            sub edi, 14
1562 loop2_pass2:
1563                            movd mm0, [esi]        ; X X X X v1 v0 v3 v2
1564                            punpcklwd mm0, mm0     ; v1 v0 v1 v0 v3 v2 v3 v2
1565                            movq mm1, mm0          ; v1 v0 v1 v0 v3 v2 v3 v2
1566                            punpckldq mm0, mm0     ; v3 v2 v3 v2 v3 v2 v3 v2
1567                            punpckhdq mm1, mm1     ; v1 v0 v1 v0 v1 v0 v1 v0
1568                            movq [edi], mm0
1569                            sub esi, 4
1570                            movq [edi + 8], mm1
1571                            //sub esi, 4
1572                            sub edi, 16
1573                            sub ecx, 2
1574                            jnz loop2_pass2
1575                            EMMS
1576                         }
1577                      }
1578
1579                      sptr -= (width_mmx*2 - 2);            // sign fixed
1580                      dp -= (width_mmx*8 - 2);            // sign fixed
1581                      for (i = width; i; i--)
1582                      {
1583                         png_byte v[8];
1584                         int j;
1585                         sptr -= 2;
1586                         png_memcpy(v, sptr, 2);
1587                         for (j = 0; j < png_pass_inc[pass]; j++)
1588                         {
1589                            dp -= 2;
1590                            png_memcpy(dp, v, 2);
1591                         }
1592                      }
1593                   }
1594                   else if (width)  // pass == 4 or 5
1595                   {
1596                      int width_mmx = ((width >> 1) << 1) ;
1597                      width -= width_mmx;
1598                      if (width_mmx)
1599                      {
1600                         _asm
1601                         {
1602                            mov esi, sptr
1603                            mov edi, dp
1604                            mov ecx, width_mmx
1605                            sub esi, 2
1606                            sub edi, 6
1607 loop2_pass4:
1608                            movd mm0, [esi]        ; X X X X v1 v0 v3 v2
1609                            punpcklwd mm0, mm0     ; v1 v0 v1 v0 v3 v2 v3 v2
1610                            sub esi, 4
1611                            movq [edi], mm0
1612                            sub edi, 8
1613                            sub ecx, 2
1614                            jnz loop2_pass4
1615                            EMMS
1616                         }
1617                      }
1618
1619                      sptr -= (width_mmx*2 - 2);            // sign fixed
1620                      dp -= (width_mmx*4 - 2);            // sign fixed
1621                      for (i = width; i; i--)
1622                      {
1623                         png_byte v[8];
1624                         int j;
1625                         sptr -= 2;
1626                         png_memcpy(v, sptr, 2);
1627                         for (j = 0; j < png_pass_inc[pass]; j++)
1628                         {
1629                            dp -= 2;
1630                            png_memcpy(dp, v, 2);
1631                         }
1632                      }
1633                   }
1634                } /* end of pixel_bytes == 2 */
1635
1636                else if (pixel_bytes == 4)
1637                {
1638                   if (((pass == 0) || (pass == 1)) && width)
1639                   {
1640                      int width_mmx = ((width >> 1) << 1) ;
1641                      width -= width_mmx;
1642                      if (width_mmx)
1643                      {
1644                         _asm
1645                         {
1646                            mov esi, sptr
1647                            mov edi, dp
1648                            mov ecx, width_mmx
1649                            sub esi, 4
1650                            sub edi, 60
1651 loop4_pass0:
1652                            movq mm0, [esi]        ; v3 v2 v1 v0 v7 v6 v5 v4
1653                            movq mm1, mm0          ; v3 v2 v1 v0 v7 v6 v5 v4
1654                            punpckldq mm0, mm0     ; v7 v6 v5 v4 v7 v6 v5 v4
1655                            punpckhdq mm1, mm1     ; v3 v2 v1 v0 v3 v2 v1 v0
1656                            movq [edi], mm0
1657                            movq [edi + 8], mm0
1658                            movq [edi + 16], mm0
1659                            movq [edi + 24], mm0
1660                            movq [edi+32], mm1
1661                            movq [edi + 40], mm1
1662                            movq [edi+ 48], mm1
1663                            sub esi, 8
1664                            movq [edi + 56], mm1
1665                            sub edi, 64
1666                            sub ecx, 2
1667                            jnz loop4_pass0
1668                            EMMS
1669                         }
1670                      }
1671
1672                      sptr -= (width_mmx*4 - 4);            // sign fixed
1673                      dp -= (width_mmx*32 - 4);            // sign fixed
1674                      for (i = width; i; i--)
1675                      {
1676                         png_byte v[8];
1677                         int j;
1678                         sptr -= 4;
1679                         png_memcpy(v, sptr, 4);
1680                         for (j = 0; j < png_pass_inc[pass]; j++)
1681                         {
1682                            dp -= 4;
1683                            png_memcpy(dp, v, 4);
1684                         }
1685                      }
1686                   }
1687                   else if (((pass == 2) || (pass == 3)) && width)
1688                   {
1689                      int width_mmx = ((width >> 1) << 1) ;
1690                      width -= width_mmx;
1691                      if (width_mmx)
1692                      {
1693                         _asm
1694                         {
1695                            mov esi, sptr
1696                            mov edi, dp
1697                            mov ecx, width_mmx
1698                            sub esi, 4
1699                            sub edi, 28
1700 loop4_pass2:
1701                            movq mm0, [esi]      ; v3 v2 v1 v0 v7 v6 v5 v4
1702                            movq mm1, mm0        ; v3 v2 v1 v0 v7 v6 v5 v4
1703                            punpckldq mm0, mm0   ; v7 v6 v5 v4 v7 v6 v5 v4
1704                            punpckhdq mm1, mm1   ; v3 v2 v1 v0 v3 v2 v1 v0
1705                            movq [edi], mm0
1706                            movq [edi + 8], mm0
1707                            movq [edi+16], mm1
1708                            movq [edi + 24], mm1
1709                            sub esi, 8
1710                            sub edi, 32
1711                            sub ecx, 2
1712                            jnz loop4_pass2
1713                            EMMS
1714                         }
1715                      }
1716
1717                      sptr -= (width_mmx*4 - 4);            // sign fixed
1718                      dp -= (width_mmx*16 - 4);            // sign fixed
1719                      for (i = width; i; i--)
1720                      {
1721                         png_byte v[8];
1722                         int j;
1723                         sptr -= 4;
1724                         png_memcpy(v, sptr, 4);
1725                         for (j = 0; j < png_pass_inc[pass]; j++)
1726                         {
1727                            dp -= 4;
1728                            png_memcpy(dp, v, 4);
1729                         }
1730                      }
1731                   }
1732                   else if (width)  // pass == 4 or 5
1733                   {
1734                      int width_mmx = ((width >> 1) << 1) ;
1735                      width -= width_mmx;
1736                      if (width_mmx)
1737                      {
1738                         _asm
1739                         {
1740                            mov esi, sptr
1741                            mov edi, dp
1742                            mov ecx, width_mmx
1743                            sub esi, 4
1744                            sub edi, 12
1745 loop4_pass4:
1746                            movq mm0, [esi]      ; v3 v2 v1 v0 v7 v6 v5 v4
1747                            movq mm1, mm0        ; v3 v2 v1 v0 v7 v6 v5 v4
1748                            punpckldq mm0, mm0   ; v7 v6 v5 v4 v7 v6 v5 v4
1749                            punpckhdq mm1, mm1   ; v3 v2 v1 v0 v3 v2 v1 v0
1750                            movq [edi], mm0
1751                            sub esi, 8
1752                            movq [edi + 8], mm1
1753                            sub edi, 16
1754                            sub ecx, 2
1755                            jnz loop4_pass4
1756                            EMMS
1757                         }
1758                      }
1759
1760                      sptr -= (width_mmx*4 - 4);          // sign fixed
1761                      dp -= (width_mmx*8 - 4);            // sign fixed
1762                      for (i = width; i; i--)
1763                      {
1764                         png_byte v[8];
1765                         int j;
1766                         sptr -= 4;
1767                         png_memcpy(v, sptr, 4);
1768                         for (j = 0; j < png_pass_inc[pass]; j++)
1769                         {
1770                            dp -= 4;
1771                            png_memcpy(dp, v, 4);
1772                         }
1773                      }
1774                   }
1775
1776                } /* end of pixel_bytes == 4 */
1777
1778                else if (pixel_bytes == 6)
1779                {
1780                   for (i = width; i; i--)
1781                   {
1782                      png_byte v[8];
1783                      int j;
1784                      png_memcpy(v, sptr, 6);
1785                      for (j = 0; j < png_pass_inc[pass]; j++)
1786                      {
1787                         png_memcpy(dp, v, 6);
1788                         dp -= 6;
1789                      }
1790                      sptr -= 6;
1791                   }
1792                } /* end of pixel_bytes == 6 */
1793
1794                else
1795                {
1796                   for (i = width; i; i--)
1797                   {
1798                      png_byte v[8];
1799                      int j;
1800                      png_memcpy(v, sptr, pixel_bytes);
1801                      for (j = 0; j < png_pass_inc[pass]; j++)
1802                      {
1803                         png_memcpy(dp, v, pixel_bytes);
1804                         dp -= pixel_bytes;
1805                      }
1806                      sptr-= pixel_bytes;
1807                   }
1808                }
1809             } /* end of mmx_supported */
1810
1811             else /* MMX not supported:  use modified C code - takes advantage
1812                   * of inlining of memcpy for a constant */
1813             {
1814                if (pixel_bytes == 1)
1815                {
1816                   for (i = width; i; i--)
1817                   {
1818                      int j;
1819                      for (j = 0; j < png_pass_inc[pass]; j++)
1820                         *dp-- = *sptr;
1821                      sptr--;
1822                   }
1823                }
1824                else if (pixel_bytes == 3)
1825                {
1826                   for (i = width; i; i--)
1827                   {
1828                      png_byte v[8];
1829                      int j;
1830                      png_memcpy(v, sptr, pixel_bytes);
1831                      for (j = 0; j < png_pass_inc[pass]; j++)
1832                      {
1833                         png_memcpy(dp, v, pixel_bytes);
1834                         dp -= pixel_bytes;
1835                      }
1836                      sptr -= pixel_bytes;
1837                   }
1838                }
1839                else if (pixel_bytes == 2)
1840                {
1841                   for (i = width; i; i--)
1842                   {
1843                      png_byte v[8];
1844                      int j;
1845                      png_memcpy(v, sptr, pixel_bytes);
1846                      for (j = 0; j < png_pass_inc[pass]; j++)
1847                      {
1848                         png_memcpy(dp, v, pixel_bytes);
1849                         dp -= pixel_bytes;
1850                      }
1851                      sptr -= pixel_bytes;
1852                   }
1853                }
1854                else if (pixel_bytes == 4)
1855                {
1856                   for (i = width; i; i--)
1857                   {
1858                      png_byte v[8];
1859                      int j;
1860                      png_memcpy(v, sptr, pixel_bytes);
1861                      for (j = 0; j < png_pass_inc[pass]; j++)
1862                      {
1863                         png_memcpy(dp, v, pixel_bytes);
1864                         dp -= pixel_bytes;
1865                      }
1866                      sptr -= pixel_bytes;
1867                   }
1868                }
1869                else if (pixel_bytes == 6)
1870                {
1871                   for (i = width; i; i--)
1872                   {
1873                      png_byte v[8];
1874                      int j;
1875                      png_memcpy(v, sptr, pixel_bytes);
1876                      for (j = 0; j < png_pass_inc[pass]; j++)
1877                      {
1878                         png_memcpy(dp, v, pixel_bytes);
1879                         dp -= pixel_bytes;
1880                      }
1881                      sptr -= pixel_bytes;
1882                   }
1883                }
1884                else
1885                {
1886                   for (i = width; i; i--)
1887                   {
1888                      png_byte v[8];
1889                      int j;
1890                      png_memcpy(v, sptr, pixel_bytes);
1891                      for (j = 0; j < png_pass_inc[pass]; j++)
1892                      {
1893                         png_memcpy(dp, v, pixel_bytes);
1894                         dp -= pixel_bytes;
1895                      }
1896                      sptr -= pixel_bytes;
1897                   }
1898                }
1899
1900             } /* end of MMX not supported */
1901             break;
1902          }
1903       } /* end switch (row_info->pixel_depth) */
1904
1905       row_info->width = final_width;
1906
1907       row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width);
1908    }
1909
1910 }
1911
1912 #endif /* PNG_READ_INTERLACING_SUPPORTED */
1913
1914
1915 // These variables are utilized in the functions below.  They are declared
1916 // globally here to ensure alignment on 8-byte boundaries.
1917
1918 union uAll {
1919    __int64 use;
1920    double  align;
1921 } LBCarryMask = {0x0101010101010101},
1922   HBClearMask = {0x7f7f7f7f7f7f7f7f},
1923   ActiveMask, ActiveMask2, ActiveMaskEnd, ShiftBpp, ShiftRem;
1924
1925
1926 // Optimized code for PNG Average filter decoder
1927 void /* PRIVATE */
1928 png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row
1929                             , png_bytep prev_row)
1930 {
1931    int bpp;
1932    png_uint_32 FullLength;
1933    png_uint_32 MMXLength;
1934    //png_uint_32 len;
1935    int diff;
1936
1937    bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
1938    FullLength  = row_info->rowbytes; // # of bytes to filter
1939    _asm {
1940          // Init address pointers and offset
1941          mov edi, row          // edi ==> Avg(x)
1942          xor ebx, ebx          // ebx ==> x
1943          mov edx, edi
1944          mov esi, prev_row           // esi ==> Prior(x)
1945          sub edx, bpp          // edx ==> Raw(x-bpp)
1946
1947          xor eax, eax
1948          // Compute the Raw value for the first bpp bytes
1949          //    Raw(x) = Avg(x) + (Prior(x)/2)
1950 davgrlp:
1951          mov al, [esi + ebx]   // Load al with Prior(x)
1952          inc ebx
1953          shr al, 1             // divide by 2
1954          add al, [edi+ebx-1]   // Add Avg(x); -1 to offset inc ebx
1955          cmp ebx, bpp
1956          mov [edi+ebx-1], al    // Write back Raw(x);
1957                             // mov does not affect flags; -1 to offset inc ebx
1958          jb davgrlp
1959          // get # of bytes to alignment
1960          mov diff, edi         // take start of row
1961          add diff, ebx         // add bpp
1962          add diff, 0xf         // add 7 + 8 to incr past alignment boundary
1963          and diff, 0xfffffff8  // mask to alignment boundary
1964          sub diff, edi         // subtract from start ==> value ebx at alignment
1965          jz davggo
1966          // fix alignment
1967          // Compute the Raw value for the bytes upto the alignment boundary
1968          //    Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
1969          xor ecx, ecx
1970 davglp1:
1971          xor eax, eax
1972          mov cl, [esi + ebx]        // load cl with Prior(x)
1973          mov al, [edx + ebx]  // load al with Raw(x-bpp)
1974          add ax, cx
1975          inc ebx
1976          shr ax, 1            // divide by 2
1977          add al, [edi+ebx-1]  // Add Avg(x); -1 to offset inc ebx
1978          cmp ebx, diff              // Check if at alignment boundary
1979          mov [edi+ebx-1], al        // Write back Raw(x);
1980                             // mov does not affect flags; -1 to offset inc ebx
1981          jb davglp1               // Repeat until at alignment boundary
1982 davggo:
1983          mov eax, FullLength
1984          mov ecx, eax
1985          sub eax, ebx          // subtract alignment fix
1986          and eax, 0x00000007   // calc bytes over mult of 8
1987          sub ecx, eax          // drop over bytes from original length
1988          mov MMXLength, ecx
1989    } // end _asm block
1990    // Now do the math for the rest of the row
1991    switch ( bpp )
1992    {
1993       case 3:
1994       {
1995          ActiveMask.use  = 0x0000000000ffffff;
1996          ShiftBpp.use = 24;    // == 3 * 8
1997          ShiftRem.use = 40;    // == 64 - 24
1998          _asm {
1999             // Re-init address pointers and offset
2000             movq mm7, ActiveMask
2001             mov ebx, diff      // ebx ==> x = offset to alignment boundary
2002             movq mm5, LBCarryMask
2003             mov edi, row       // edi ==> Avg(x)
2004             movq mm4, HBClearMask
2005             mov esi, prev_row        // esi ==> Prior(x)
2006             // PRIME the pump (load the first Raw(x-bpp) data set
2007             movq mm2, [edi + ebx - 8]  // Load previous aligned 8 bytes
2008                                // (we correct position in loop below)
2009 davg3lp:
2010             movq mm0, [edi + ebx]      // Load mm0 with Avg(x)
2011             // Add (Prev_row/2) to Average
2012             movq mm3, mm5
2013             psrlq mm2, ShiftRem      // Correct position Raw(x-bpp) data
2014             movq mm1, [esi + ebx]    // Load mm1 with Prior(x)
2015             movq mm6, mm7
2016             pand mm3, mm1      // get lsb for each prev_row byte
2017             psrlq mm1, 1       // divide prev_row bytes by 2
2018             pand  mm1, mm4     // clear invalid bit 7 of each byte
2019             paddb mm0, mm1     // add (Prev_row/2) to Avg for each byte
2020             // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry
2021             movq mm1, mm3      // now use mm1 for getting LBCarrys
2022             pand mm1, mm2      // get LBCarrys for each byte where both
2023                                // lsb's were == 1 (Only valid for active group)
2024             psrlq mm2, 1       // divide raw bytes by 2
2025             pand  mm2, mm4     // clear invalid bit 7 of each byte
2026             paddb mm2, mm1     // add LBCarrys to (Raw(x-bpp)/2) for each byte
2027             pand mm2, mm6      // Leave only Active Group 1 bytes to add to Avg
2028             paddb mm0, mm2     // add (Raw/2) + LBCarrys to Avg for each Active
2029                                //  byte
2030             // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry
2031             psllq mm6, ShiftBpp  // shift the mm6 mask to cover bytes 3-5
2032             movq mm2, mm0        // mov updated Raws to mm2
2033             psllq mm2, ShiftBpp  // shift data to position correctly
2034             movq mm1, mm3        // now use mm1 for getting LBCarrys
2035             pand mm1, mm2      // get LBCarrys for each byte where both
2036                                // lsb's were == 1 (Only valid for active group)
2037             psrlq mm2, 1       // divide raw bytes by 2
2038             pand  mm2, mm4     // clear invalid bit 7 of each byte
2039             paddb mm2, mm1     // add LBCarrys to (Raw(x-bpp)/2) for each byte
2040             pand mm2, mm6      // Leave only Active Group 2 bytes to add to Avg
2041             paddb mm0, mm2     // add (Raw/2) + LBCarrys to Avg for each Active
2042                                //  byte
2043
2044             // Add 3rd active group (Raw(x-bpp)/2) to Average with LBCarry
2045             psllq mm6, ShiftBpp  // shift the mm6 mask to cover the last two
2046                                  // bytes
2047             movq mm2, mm0        // mov updated Raws to mm2
2048             psllq mm2, ShiftBpp  // shift data to position correctly
2049                               // Data only needs to be shifted once here to
2050                               // get the correct x-bpp offset.
2051             movq mm1, mm3     // now use mm1 for getting LBCarrys
2052             pand mm1, mm2     // get LBCarrys for each byte where both
2053                               // lsb's were == 1 (Only valid for active group)
2054             psrlq mm2, 1      // divide raw bytes by 2
2055             pand  mm2, mm4    // clear invalid bit 7 of each byte
2056             paddb mm2, mm1    // add LBCarrys to (Raw(x-bpp)/2) for each byte
2057             pand mm2, mm6     // Leave only Active Group 2 bytes to add to Avg
2058             add ebx, 8
2059             paddb mm0, mm2    // add (Raw/2) + LBCarrys to Avg for each Active
2060                               // byte
2061
2062             // Now ready to write back to memory
2063             movq [edi + ebx - 8], mm0
2064             // Move updated Raw(x) to use as Raw(x-bpp) for next loop
2065             cmp ebx, MMXLength
2066             movq mm2, mm0     // mov updated Raw(x) to mm2
2067             jb davg3lp
2068          } // end _asm block
2069       }
2070       break;
2071
2072       case 6:
2073       case 4:
2074       case 7:
2075       case 5:
2076       {
2077          ActiveMask.use  = 0xffffffffffffffff;  // use shift below to clear
2078                                                 // appropriate inactive bytes
2079          ShiftBpp.use = bpp << 3;
2080          ShiftRem.use = 64 - ShiftBpp.use;
2081          _asm {
2082             movq mm4, HBClearMask
2083             // Re-init address pointers and offset
2084             mov ebx, diff       // ebx ==> x = offset to alignment boundary
2085             // Load ActiveMask and clear all bytes except for 1st active group
2086             movq mm7, ActiveMask
2087             mov edi, row         // edi ==> Avg(x)
2088             psrlq mm7, ShiftRem
2089             mov esi, prev_row    // esi ==> Prior(x)
2090             movq mm6, mm7
2091             movq mm5, LBCarryMask
2092             psllq mm6, ShiftBpp  // Create mask for 2nd active group
2093             // PRIME the pump (load the first Raw(x-bpp) data set
2094             movq mm2, [edi + ebx - 8]  // Load previous aligned 8 bytes
2095                                  // (we correct position in loop below)
2096 davg4lp:
2097             movq mm0, [edi + ebx]
2098             psrlq mm2, ShiftRem  // shift data to position correctly
2099             movq mm1, [esi + ebx]
2100             // Add (Prev_row/2) to Average
2101             movq mm3, mm5
2102             pand mm3, mm1     // get lsb for each prev_row byte
2103             psrlq mm1, 1      // divide prev_row bytes by 2
2104             pand  mm1, mm4    // clear invalid bit 7 of each byte
2105             paddb mm0, mm1    // add (Prev_row/2) to Avg for each byte
2106             // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry
2107             movq mm1, mm3     // now use mm1 for getting LBCarrys
2108             pand mm1, mm2     // get LBCarrys for each byte where both
2109                               // lsb's were == 1 (Only valid for active group)
2110             psrlq mm2, 1      // divide raw bytes by 2
2111             pand  mm2, mm4    // clear invalid bit 7 of each byte
2112             paddb mm2, mm1    // add LBCarrys to (Raw(x-bpp)/2) for each byte
2113             pand mm2, mm7     // Leave only Active Group 1 bytes to add to Avg
2114             paddb mm0, mm2    // add (Raw/2) + LBCarrys to Avg for each Active
2115                               // byte
2116             // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry
2117             movq mm2, mm0     // mov updated Raws to mm2
2118             psllq mm2, ShiftBpp // shift data to position correctly
2119             add ebx, 8
2120             movq mm1, mm3     // now use mm1 for getting LBCarrys
2121             pand mm1, mm2     // get LBCarrys for each byte where both
2122                               // lsb's were == 1 (Only valid for active group)
2123             psrlq mm2, 1      // divide raw bytes by 2
2124             pand  mm2, mm4    // clear invalid bit 7 of each byte
2125             paddb mm2, mm1    // add LBCarrys to (Raw(x-bpp)/2) for each byte
2126             pand mm2, mm6     // Leave only Active Group 2 bytes to add to Avg
2127             paddb mm0, mm2    // add (Raw/2) + LBCarrys to Avg for each Active
2128                               // byte
2129             cmp ebx, MMXLength
2130             // Now ready to write back to memory
2131             movq [edi + ebx - 8], mm0
2132             // Prep Raw(x-bpp) for next loop
2133             movq mm2, mm0     // mov updated Raws to mm2
2134             jb davg4lp
2135          } // end _asm block
2136       }
2137       break;
2138       case 2:
2139       {
2140          ActiveMask.use  = 0x000000000000ffff;
2141          ShiftBpp.use = 16;   // == 2 * 8     [BUGFIX]
2142          ShiftRem.use = 48;   // == 64 - 16   [BUGFIX]
2143          _asm {
2144             // Load ActiveMask
2145             movq mm7, ActiveMask
2146             // Re-init address pointers and offset
2147             mov ebx, diff     // ebx ==> x = offset to alignment boundary
2148             movq mm5, LBCarryMask
2149             mov edi, row      // edi ==> Avg(x)
2150             movq mm4, HBClearMask
2151             mov esi, prev_row  // esi ==> Prior(x)
2152             // PRIME the pump (load the first Raw(x-bpp) data set
2153             movq mm2, [edi + ebx - 8]  // Load previous aligned 8 bytes
2154                               // (we correct position in loop below)
2155 davg2lp:
2156             movq mm0, [edi + ebx]
2157             psrlq mm2, ShiftRem  // shift data to position correctly   [BUGFIX]
2158             movq mm1, [esi + ebx]
2159             // Add (Prev_row/2) to Average
2160             movq mm3, mm5
2161             pand mm3, mm1     // get lsb for each prev_row byte
2162             psrlq mm1, 1      // divide prev_row bytes by 2
2163             pand  mm1, mm4    // clear invalid bit 7 of each byte
2164             movq mm6, mm7
2165             paddb mm0, mm1    // add (Prev_row/2) to Avg for each byte
2166             // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry
2167             movq mm1, mm3     // now use mm1 for getting LBCarrys
2168             pand mm1, mm2     // get LBCarrys for each byte where both
2169                               // lsb's were == 1 (Only valid for active group)
2170             psrlq mm2, 1      // divide raw bytes by 2
2171             pand  mm2, mm4    // clear invalid bit 7 of each byte
2172             paddb mm2, mm1    // add LBCarrys to (Raw(x-bpp)/2) for each byte
2173             pand mm2, mm6     // Leave only Active Group 1 bytes to add to Avg
2174             paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte
2175             // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry
2176             psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 2 & 3
2177             movq mm2, mm0       // mov updated Raws to mm2
2178             psllq mm2, ShiftBpp // shift data to position correctly
2179             movq mm1, mm3       // now use mm1 for getting LBCarrys
2180             pand mm1, mm2       // get LBCarrys for each byte where both
2181                                 // lsb's were == 1 (Only valid for active group)
2182             psrlq mm2, 1        // divide raw bytes by 2
2183             pand  mm2, mm4      // clear invalid bit 7 of each byte
2184             paddb mm2, mm1      // add LBCarrys to (Raw(x-bpp)/2) for each byte
2185             pand mm2, mm6       // Leave only Active Group 2 bytes to add to Avg
2186             paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte
2187
2188             // Add rdd active group (Raw(x-bpp)/2) to Average with LBCarry
2189             psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 4 & 5
2190             movq mm2, mm0       // mov updated Raws to mm2
2191             psllq mm2, ShiftBpp // shift data to position correctly
2192                                 // Data only needs to be shifted once here to
2193                                 // get the correct x-bpp offset.
2194             movq mm1, mm3       // now use mm1 for getting LBCarrys
2195             pand mm1, mm2       // get LBCarrys for each byte where both
2196                                 // lsb's were == 1 (Only valid for active group)
2197             psrlq mm2, 1        // divide raw bytes by 2
2198             pand  mm2, mm4      // clear invalid bit 7 of each byte
2199             paddb mm2, mm1      // add LBCarrys to (Raw(x-bpp)/2) for each byte
2200             pand mm2, mm6       // Leave only Active Group 2 bytes to add to Avg
2201             paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte
2202
2203             // Add 4th active group (Raw(x-bpp)/2) to Average with LBCarry
2204             psllq mm6, ShiftBpp  // shift the mm6 mask to cover bytes 6 & 7
2205             movq mm2, mm0        // mov updated Raws to mm2
2206             psllq mm2, ShiftBpp  // shift data to position correctly
2207                                  // Data only needs to be shifted once here to
2208                                  // get the correct x-bpp offset.
2209             add ebx, 8
2210             movq mm1, mm3    // now use mm1 for getting LBCarrys
2211             pand mm1, mm2    // get LBCarrys for each byte where both
2212                              // lsb's were == 1 (Only valid for active group)
2213             psrlq mm2, 1     // divide raw bytes by 2
2214             pand  mm2, mm4   // clear invalid bit 7 of each byte
2215             paddb mm2, mm1   // add LBCarrys to (Raw(x-bpp)/2) for each byte
2216             pand mm2, mm6    // Leave only Active Group 2 bytes to add to Avg
2217             paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte
2218
2219             cmp ebx, MMXLength
2220             // Now ready to write back to memory
2221             movq [edi + ebx - 8], mm0
2222             // Prep Raw(x-bpp) for next loop
2223             movq mm2, mm0    // mov updated Raws to mm2
2224             jb davg2lp
2225         } // end _asm block
2226       }
2227       break;
2228
2229       case 1:                 // bpp == 1
2230       {
2231          _asm {
2232             // Re-init address pointers and offset
2233             mov ebx, diff     // ebx ==> x = offset to alignment boundary
2234             mov edi, row      // edi ==> Avg(x)
2235             cmp ebx, FullLength  // Test if offset at end of array
2236             jnb davg1end
2237             // Do Paeth decode for remaining bytes
2238             mov esi, prev_row    // esi ==> Prior(x)
2239             mov edx, edi
2240             xor ecx, ecx         // zero ecx before using cl & cx in loop below
2241             sub edx, bpp         // edx ==> Raw(x-bpp)
2242 davg1lp:
2243             // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
2244             xor eax, eax
2245             mov cl, [esi + ebx]  // load cl with Prior(x)
2246             mov al, [edx + ebx]  // load al with Raw(x-bpp)
2247             add ax, cx
2248             inc ebx
2249             shr ax, 1            // divide by 2
2250             add al, [edi+ebx-1]  // Add Avg(x); -1 to offset inc ebx
2251             cmp ebx, FullLength  // Check if at end of array
2252             mov [edi+ebx-1], al  // Write back Raw(x);
2253                          // mov does not affect flags; -1 to offset inc ebx
2254             jb davg1lp
2255 davg1end:
2256          } // end _asm block
2257       }
2258       return;
2259
2260       case 8:             // bpp == 8
2261       {
2262          _asm {
2263             // Re-init address pointers and offset
2264             mov ebx, diff           // ebx ==> x = offset to alignment boundary
2265             movq mm5, LBCarryMask
2266             mov edi, row            // edi ==> Avg(x)
2267             movq mm4, HBClearMask
2268             mov esi, prev_row       // esi ==> Prior(x)
2269             // PRIME the pump (load the first Raw(x-bpp) data set
2270             movq mm2, [edi + ebx - 8]  // Load previous aligned 8 bytes
2271                                 // (NO NEED to correct position in loop below)
2272 davg8lp:
2273             movq mm0, [edi + ebx]
2274             movq mm3, mm5
2275             movq mm1, [esi + ebx]
2276             add ebx, 8
2277             pand mm3, mm1       // get lsb for each prev_row byte
2278             psrlq mm1, 1        // divide prev_row bytes by 2
2279             pand mm3, mm2       // get LBCarrys for each byte where both
2280                                 // lsb's were == 1
2281             psrlq mm2, 1        // divide raw bytes by 2
2282             pand  mm1, mm4      // clear invalid bit 7 of each byte
2283             paddb mm0, mm3      // add LBCarrys to Avg for each byte
2284             pand  mm2, mm4      // clear invalid bit 7 of each byte
2285             paddb mm0, mm1      // add (Prev_row/2) to Avg for each byte
2286             paddb mm0, mm2      // add (Raw/2) to Avg for each byte
2287             cmp ebx, MMXLength
2288             movq [edi + ebx - 8], mm0
2289             movq mm2, mm0       // reuse as Raw(x-bpp)
2290             jb davg8lp
2291         } // end _asm block
2292       }
2293       break;
2294       default:                  // bpp greater than 8
2295       {
2296         _asm {
2297             movq mm5, LBCarryMask
2298             // Re-init address pointers and offset
2299             mov ebx, diff       // ebx ==> x = offset to alignment boundary
2300             mov edi, row        // edi ==> Avg(x)
2301             movq mm4, HBClearMask
2302             mov edx, edi
2303             mov esi, prev_row   // esi ==> Prior(x)
2304             sub edx, bpp        // edx ==> Raw(x-bpp)
2305 davgAlp:
2306             movq mm0, [edi + ebx]
2307             movq mm3, mm5
2308             movq mm1, [esi + ebx]
2309             pand mm3, mm1       // get lsb for each prev_row byte
2310             movq mm2, [edx + ebx]
2311             psrlq mm1, 1        // divide prev_row bytes by 2
2312             pand mm3, mm2       // get LBCarrys for each byte where both
2313                                 // lsb's were == 1
2314             psrlq mm2, 1        // divide raw bytes by 2
2315             pand  mm1, mm4      // clear invalid bit 7 of each byte
2316             paddb mm0, mm3      // add LBCarrys to Avg for each byte
2317             pand  mm2, mm4      // clear invalid bit 7 of each byte
2318             paddb mm0, mm1      // add (Prev_row/2) to Avg for each byte
2319             add ebx, 8
2320             paddb mm0, mm2      // add (Raw/2) to Avg for each byte
2321             cmp ebx, MMXLength
2322             movq [edi + ebx - 8], mm0
2323             jb davgAlp
2324         } // end _asm block
2325       }
2326       break;
2327    }                         // end switch ( bpp )
2328
2329    _asm {
2330          // MMX acceleration complete now do clean-up
2331          // Check if any remaining bytes left to decode
2332          mov ebx, MMXLength    // ebx ==> x = offset bytes remaining after MMX
2333          mov edi, row          // edi ==> Avg(x)
2334          cmp ebx, FullLength   // Test if offset at end of array
2335          jnb davgend
2336          // Do Paeth decode for remaining bytes
2337          mov esi, prev_row     // esi ==> Prior(x)
2338          mov edx, edi
2339          xor ecx, ecx          // zero ecx before using cl & cx in loop below
2340          sub edx, bpp          // edx ==> Raw(x-bpp)
2341 davglp2:
2342          // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
2343          xor eax, eax
2344          mov cl, [esi + ebx]   // load cl with Prior(x)
2345          mov al, [edx + ebx]   // load al with Raw(x-bpp)
2346          add ax, cx
2347          inc ebx
2348          shr ax, 1              // divide by 2
2349          add al, [edi+ebx-1]    // Add Avg(x); -1 to offset inc ebx
2350          cmp ebx, FullLength    // Check if at end of array
2351          mov [edi+ebx-1], al    // Write back Raw(x);
2352                           // mov does not affect flags; -1 to offset inc ebx
2353          jb davglp2
2354 davgend:
2355          emms             // End MMX instructions; prep for possible FP instrs.
2356    } // end _asm block
2357 }
2358
2359 // Optimized code for PNG Paeth filter decoder
2360 void /* PRIVATE */
2361 png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row,
2362                               png_bytep prev_row)
2363 {
2364    png_uint_32 FullLength;
2365    png_uint_32 MMXLength;
2366    //png_uint_32 len;
2367    int bpp;
2368    int diff;
2369    //int ptemp;
2370    int patemp, pbtemp, pctemp;
2371
2372    bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
2373    FullLength  = row_info->rowbytes; // # of bytes to filter
2374    _asm
2375    {
2376          xor ebx, ebx        // ebx ==> x offset
2377          mov edi, row
2378          xor edx, edx        // edx ==> x-bpp offset
2379          mov esi, prev_row
2380          xor eax, eax
2381
2382          // Compute the Raw value for the first bpp bytes
2383          // Note: the formula works out to be always
2384          //   Paeth(x) = Raw(x) + Prior(x)      where x < bpp
2385 dpthrlp:
2386          mov al, [edi + ebx]
2387          add al, [esi + ebx]
2388          inc ebx
2389          cmp ebx, bpp
2390          mov [edi + ebx - 1], al
2391          jb dpthrlp
2392          // get # of bytes to alignment
2393          mov diff, edi         // take start of row
2394          add diff, ebx         // add bpp
2395          xor ecx, ecx
2396          add diff, 0xf         // add 7 + 8 to incr past alignment boundary
2397          and diff, 0xfffffff8  // mask to alignment boundary
2398          sub diff, edi         // subtract from start ==> value ebx at alignment
2399          jz dpthgo
2400          // fix alignment
2401 dpthlp1:
2402          xor eax, eax
2403          // pav = p - a = (a + b - c) - a = b - c
2404          mov al, [esi + ebx]   // load Prior(x) into al
2405          mov cl, [esi + edx]   // load Prior(x-bpp) into cl
2406          sub eax, ecx          // subtract Prior(x-bpp)
2407          mov patemp, eax       // Save pav for later use
2408          xor eax, eax
2409          // pbv = p - b = (a + b - c) - b = a - c
2410          mov al, [edi + edx]   // load Raw(x-bpp) into al
2411          sub eax, ecx          // subtract Prior(x-bpp)
2412          mov ecx, eax
2413          // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
2414          add eax, patemp       // pcv = pav + pbv
2415          // pc = abs(pcv)
2416          test eax, 0x80000000
2417          jz dpthpca
2418          neg eax               // reverse sign of neg values
2419 dpthpca:
2420          mov pctemp, eax       // save pc for later use
2421          // pb = abs(pbv)
2422          test ecx, 0x80000000
2423          jz dpthpba
2424          neg ecx               // reverse sign of neg values
2425 dpthpba:
2426          mov pbtemp, ecx       // save pb for later use
2427          // pa = abs(pav)
2428          mov eax, patemp
2429          test eax, 0x80000000
2430          jz dpthpaa
2431          neg eax               // reverse sign of neg values
2432 dpthpaa:
2433          mov patemp, eax       // save pa for later use
2434          // test if pa <= pb
2435          cmp eax, ecx
2436          jna dpthabb
2437          // pa > pb; now test if pb <= pc
2438          cmp ecx, pctemp
2439          jna dpthbbc
2440          // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
2441          mov cl, [esi + edx]  // load Prior(x-bpp) into cl
2442          jmp dpthpaeth
2443 dpthbbc:
2444          // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
2445          mov cl, [esi + ebx]   // load Prior(x) into cl
2446          jmp dpthpaeth
2447 dpthabb:
2448          // pa <= pb; now test if pa <= pc
2449          cmp eax, pctemp
2450          jna dpthabc
2451          // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
2452          mov cl, [esi + edx]  // load Prior(x-bpp) into cl
2453          jmp dpthpaeth
2454 dpthabc:
2455          // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
2456          mov cl, [edi + edx]  // load Raw(x-bpp) into cl
2457 dpthpaeth:
2458          inc ebx
2459          inc edx
2460          // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
2461          add [edi + ebx - 1], cl
2462          cmp ebx, diff
2463          jb dpthlp1
2464 dpthgo:
2465          mov ecx, FullLength
2466          mov eax, ecx
2467          sub eax, ebx          // subtract alignment fix
2468          and eax, 0x00000007   // calc bytes over mult of 8
2469          sub ecx, eax          // drop over bytes from original length
2470          mov MMXLength, ecx
2471    } // end _asm block
2472    // Now do the math for the rest of the row
2473    switch ( bpp )
2474    {
2475       case 3:
2476       {
2477          ActiveMask.use = 0x0000000000ffffff;
2478          ActiveMaskEnd.use = 0xffff000000000000;
2479          ShiftBpp.use = 24;    // == bpp(3) * 8
2480          ShiftRem.use = 40;    // == 64 - 24
2481          _asm
2482          {
2483             mov ebx, diff
2484             mov edi, row
2485             mov esi, prev_row
2486             pxor mm0, mm0
2487             // PRIME the pump (load the first Raw(x-bpp) data set
2488             movq mm1, [edi+ebx-8]
2489 dpth3lp:
2490             psrlq mm1, ShiftRem     // shift last 3 bytes to 1st 3 bytes
2491             movq mm2, [esi + ebx]   // load b=Prior(x)
2492             punpcklbw mm1, mm0      // Unpack High bytes of a
2493             movq mm3, [esi+ebx-8]   // Prep c=Prior(x-bpp) bytes
2494             punpcklbw mm2, mm0      // Unpack High bytes of b
2495             psrlq mm3, ShiftRem     // shift last 3 bytes to 1st 3 bytes
2496             // pav = p - a = (a + b - c) - a = b - c
2497             movq mm4, mm2
2498             punpcklbw mm3, mm0      // Unpack High bytes of c
2499             // pbv = p - b = (a + b - c) - b = a - c
2500             movq mm5, mm1
2501             psubw mm4, mm3
2502             pxor mm7, mm7
2503             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
2504             movq mm6, mm4
2505             psubw mm5, mm3
2506
2507             // pa = abs(p-a) = abs(pav)
2508             // pb = abs(p-b) = abs(pbv)
2509             // pc = abs(p-c) = abs(pcv)
2510             pcmpgtw mm0, mm4    // Create mask pav bytes < 0
2511             paddw mm6, mm5
2512             pand mm0, mm4       // Only pav bytes < 0 in mm7
2513             pcmpgtw mm7, mm5    // Create mask pbv bytes < 0
2514             psubw mm4, mm0
2515             pand mm7, mm5       // Only pbv bytes < 0 in mm0
2516             psubw mm4, mm0
2517             psubw mm5, mm7
2518             pxor mm0, mm0
2519             pcmpgtw mm0, mm6    // Create mask pcv bytes < 0
2520             pand mm0, mm6       // Only pav bytes < 0 in mm7
2521             psubw mm5, mm7
2522             psubw mm6, mm0
2523             //  test pa <= pb
2524             movq mm7, mm4
2525             psubw mm6, mm0
2526             pcmpgtw mm7, mm5    // pa > pb?
2527             movq mm0, mm7
2528             // use mm7 mask to merge pa & pb
2529             pand mm5, mm7
2530             // use mm0 mask copy to merge a & b
2531             pand mm2, mm0
2532             pandn mm7, mm4
2533             pandn mm0, mm1
2534             paddw mm7, mm5
2535             paddw mm0, mm2
2536             //  test  ((pa <= pb)? pa:pb) <= pc
2537             pcmpgtw mm7, mm6       // pab > pc?
2538             pxor mm1, mm1
2539             pand mm3, mm7
2540             pandn mm7, mm0
2541             paddw mm7, mm3
2542             pxor mm0, mm0
2543             packuswb mm7, mm1
2544             movq mm3, [esi + ebx]   // load c=Prior(x-bpp)
2545             pand mm7, ActiveMask
2546             movq mm2, mm3           // load b=Prior(x) step 1
2547             paddb mm7, [edi + ebx]  // add Paeth predictor with Raw(x)
2548             punpcklbw mm3, mm0      // Unpack High bytes of c
2549             movq [edi + ebx], mm7   // write back updated value
2550             movq mm1, mm7           // Now mm1 will be used as Raw(x-bpp)
2551             // Now do Paeth for 2nd set of bytes (3-5)
2552             psrlq mm2, ShiftBpp     // load b=Prior(x) step 2
2553             punpcklbw mm1, mm0      // Unpack High bytes of a
2554             pxor mm7, mm7
2555             punpcklbw mm2, mm0      // Unpack High bytes of b
2556             // pbv = p - b = (a + b - c) - b = a - c
2557             movq mm5, mm1
2558             // pav = p - a = (a + b - c) - a = b - c
2559             movq mm4, mm2
2560             psubw mm5, mm3
2561             psubw mm4, mm3
2562             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) =
2563             //       pav + pbv = pbv + pav
2564             movq mm6, mm5
2565             paddw mm6, mm4
2566
2567             // pa = abs(p-a) = abs(pav)
2568             // pb = abs(p-b) = abs(pbv)
2569             // pc = abs(p-c) = abs(pcv)
2570             pcmpgtw mm0, mm5       // Create mask pbv bytes < 0
2571             pcmpgtw mm7, mm4       // Create mask pav bytes < 0
2572             pand mm0, mm5          // Only pbv bytes < 0 in mm0
2573             pand mm7, mm4          // Only pav bytes < 0 in mm7
2574             psubw mm5, mm0
2575             psubw mm4, mm7
2576             psubw mm5, mm0
2577             psubw mm4, mm7
2578             pxor mm0, mm0
2579             pcmpgtw mm0, mm6       // Create mask pcv bytes < 0
2580             pand mm0, mm6          // Only pav bytes < 0 in mm7
2581             psubw mm6, mm0
2582             //  test pa <= pb
2583             movq mm7, mm4
2584             psubw mm6, mm0
2585             pcmpgtw mm7, mm5       // pa > pb?
2586             movq mm0, mm7
2587             // use mm7 mask to merge pa & pb
2588             pand mm5, mm7
2589             // use mm0 mask copy to merge a & b
2590             pand mm2, mm0
2591             pandn mm7, mm4
2592             pandn mm0, mm1
2593             paddw mm7, mm5
2594             paddw mm0, mm2
2595             //  test  ((pa <= pb)? pa:pb) <= pc
2596             pcmpgtw mm7, mm6       // pab > pc?
2597             movq mm2, [esi + ebx]  // load b=Prior(x)
2598             pand mm3, mm7
2599             pandn mm7, mm0
2600             pxor mm1, mm1
2601             paddw mm7, mm3
2602             pxor mm0, mm0
2603             packuswb mm7, mm1
2604             movq mm3, mm2           // load c=Prior(x-bpp) step 1
2605             pand mm7, ActiveMask
2606             punpckhbw mm2, mm0      // Unpack High bytes of b
2607             psllq mm7, ShiftBpp     // Shift bytes to 2nd group of 3 bytes
2608              // pav = p - a = (a + b - c) - a = b - c
2609             movq mm4, mm2
2610             paddb mm7, [edi + ebx]  // add Paeth predictor with Raw(x)
2611             psllq mm3, ShiftBpp     // load c=Prior(x-bpp) step 2
2612             movq [edi + ebx], mm7   // write back updated value
2613             movq mm1, mm7
2614             punpckhbw mm3, mm0      // Unpack High bytes of c
2615             psllq mm1, ShiftBpp     // Shift bytes
2616                                     // Now mm1 will be used as Raw(x-bpp)
2617             // Now do Paeth for 3rd, and final, set of bytes (6-7)
2618             pxor mm7, mm7
2619             punpckhbw mm1, mm0      // Unpack High bytes of a
2620             psubw mm4, mm3
2621             // pbv = p - b = (a + b - c) - b = a - c
2622             movq mm5, mm1
2623             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
2624             movq mm6, mm4
2625             psubw mm5, mm3
2626             pxor mm0, mm0
2627             paddw mm6, mm5
2628
2629             // pa = abs(p-a) = abs(pav)
2630             // pb = abs(p-b) = abs(pbv)
2631             // pc = abs(p-c) = abs(pcv)
2632             pcmpgtw mm0, mm4    // Create mask pav bytes < 0
2633             pcmpgtw mm7, mm5    // Create mask pbv bytes < 0
2634             pand mm0, mm4       // Only pav bytes < 0 in mm7
2635             pand mm7, mm5       // Only pbv bytes < 0 in mm0
2636             psubw mm4, mm0
2637             psubw mm5, mm7
2638             psubw mm4, mm0
2639             psubw mm5, mm7
2640             pxor mm0, mm0
2641             pcmpgtw mm0, mm6    // Create mask pcv bytes < 0
2642             pand mm0, mm6       // Only pav bytes < 0 in mm7
2643             psubw mm6, mm0
2644             //  test pa <= pb
2645             movq mm7, mm4
2646             psubw mm6, mm0
2647             pcmpgtw mm7, mm5    // pa > pb?
2648             movq mm0, mm7
2649             // use mm0 mask copy to merge a & b
2650             pand mm2, mm0
2651             // use mm7 mask to merge pa & pb
2652             pand mm5, mm7
2653             pandn mm0, mm1
2654             pandn mm7, mm4
2655             paddw mm0, mm2
2656             paddw mm7, mm5
2657             //  test  ((pa <= pb)? pa:pb) <= pc
2658             pcmpgtw mm7, mm6    // pab > pc?
2659             pand mm3, mm7
2660             pandn mm7, mm0
2661             paddw mm7, mm3
2662             pxor mm1, mm1
2663             packuswb mm1, mm7
2664             // Step ebx to next set of 8 bytes and repeat loop til done
2665             add ebx, 8
2666             pand mm1, ActiveMaskEnd
2667             paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x)
2668
2669             cmp ebx, MMXLength
2670             pxor mm0, mm0              // pxor does not affect flags
2671             movq [edi + ebx - 8], mm1  // write back updated value
2672                                  // mm1 will be used as Raw(x-bpp) next loop
2673                            // mm3 ready to be used as Prior(x-bpp) next loop
2674             jb dpth3lp
2675          } // end _asm block
2676       }
2677       break;
2678
2679       case 6:
2680       case 7:
2681       case 5:
2682       {
2683          ActiveMask.use  = 0x00000000ffffffff;
2684          ActiveMask2.use = 0xffffffff00000000;
2685          ShiftBpp.use = bpp << 3;    // == bpp * 8
2686          ShiftRem.use = 64 - ShiftBpp.use;
2687          _asm
2688          {
2689             mov ebx, diff
2690             mov edi, row
2691             mov esi, prev_row
2692             // PRIME the pump (load the first Raw(x-bpp) data set
2693             movq mm1, [edi+ebx-8]
2694             pxor mm0, mm0
2695 dpth6lp:
2696             // Must shift to position Raw(x-bpp) data
2697             psrlq mm1, ShiftRem
2698             // Do first set of 4 bytes
2699             movq mm3, [esi+ebx-8]      // read c=Prior(x-bpp) bytes
2700             punpcklbw mm1, mm0      // Unpack Low bytes of a
2701             movq mm2, [esi + ebx]   // load b=Prior(x)
2702             punpcklbw mm2, mm0      // Unpack Low bytes of b
2703             // Must shift to position Prior(x-bpp) data
2704             psrlq mm3, ShiftRem
2705             // pav = p - a = (a + b - c) - a = b - c
2706             movq mm4, mm2
2707             punpcklbw mm3, mm0      // Unpack Low bytes of c
2708             // pbv = p - b = (a + b - c) - b = a - c
2709             movq mm5, mm1
2710             psubw mm4, mm3
2711             pxor mm7, mm7
2712             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
2713             movq mm6, mm4
2714             psubw mm5, mm3
2715             // pa = abs(p-a) = abs(pav)
2716             // pb = abs(p-b) = abs(pbv)
2717             // pc = abs(p-c) = abs(pcv)
2718             pcmpgtw mm0, mm4    // Create mask pav bytes < 0
2719             paddw mm6, mm5
2720             pand mm0, mm4       // Only pav bytes < 0 in mm7
2721             pcmpgtw mm7, mm5    // Create mask pbv bytes < 0
2722             psubw mm4, mm0
2723             pand mm7, mm5       // Only pbv bytes < 0 in mm0
2724             psubw mm4, mm0
2725             psubw mm5, mm7
2726             pxor mm0, mm0
2727             pcmpgtw mm0, mm6    // Create mask pcv bytes < 0
2728             pand mm0, mm6       // Only pav bytes < 0 in mm7
2729             psubw mm5, mm7
2730             psubw mm6, mm0
2731             //  test pa <= pb
2732             movq mm7, mm4
2733             psubw mm6, mm0
2734             pcmpgtw mm7, mm5    // pa > pb?
2735             movq mm0, mm7
2736             // use mm7 mask to merge pa & pb
2737             pand mm5, mm7
2738             // use mm0 mask copy to merge a & b
2739             pand mm2, mm0
2740             pandn mm7, mm4
2741             pandn mm0, mm1
2742             paddw mm7, mm5
2743             paddw mm0, mm2
2744             //  test  ((pa <= pb)? pa:pb) <= pc
2745             pcmpgtw mm7, mm6    // pab > pc?
2746             pxor mm1, mm1
2747             pand mm3, mm7
2748             pandn mm7, mm0
2749             paddw mm7, mm3
2750             pxor mm0, mm0
2751             packuswb mm7, mm1
2752             movq mm3, [esi + ebx - 8]  // load c=Prior(x-bpp)
2753             pand mm7, ActiveMask
2754             psrlq mm3, ShiftRem
2755             movq mm2, [esi + ebx]      // load b=Prior(x) step 1
2756             paddb mm7, [edi + ebx]     // add Paeth predictor with Raw(x)
2757             movq mm6, mm2
2758             movq [edi + ebx], mm7      // write back updated value
2759             movq mm1, [edi+ebx-8]
2760             psllq mm6, ShiftBpp
2761             movq mm5, mm7
2762             psrlq mm1, ShiftRem
2763             por mm3, mm6
2764             psllq mm5, ShiftBpp
2765             punpckhbw mm3, mm0         // Unpack High bytes of c
2766             por mm1, mm5
2767             // Do second set of 4 bytes
2768             punpckhbw mm2, mm0         // Unpack High bytes of b
2769             punpckhbw mm1, mm0         // Unpack High bytes of a
2770             // pav = p - a = (a + b - c) - a = b - c
2771             movq mm4, mm2
2772             // pbv = p - b = (a + b - c) - b = a - c
2773             movq mm5, mm1
2774             psubw mm4, mm3
2775             pxor mm7, mm7
2776             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
2777             movq mm6, mm4
2778             psubw mm5, mm3
2779             // pa = abs(p-a) = abs(pav)
2780             // pb = abs(p-b) = abs(pbv)
2781             // pc = abs(p-c) = abs(pcv)
2782             pcmpgtw mm0, mm4       // Create mask pav bytes < 0
2783             paddw mm6, mm5
2784             pand mm0, mm4          // Only pav bytes < 0 in mm7
2785             pcmpgtw mm7, mm5       // Create mask pbv bytes < 0
2786             psubw mm4, mm0
2787             pand mm7, mm5          // Only pbv bytes < 0 in mm0
2788             psubw mm4, mm0
2789             psubw mm5, mm7
2790             pxor mm0, mm0
2791             pcmpgtw mm0, mm6       // Create mask pcv bytes < 0
2792             pand mm0, mm6          // Only pav bytes < 0 in mm7
2793             psubw mm5, mm7
2794             psubw mm6, mm0
2795             //  test pa <= pb
2796             movq mm7, mm4
2797             psubw mm6, mm0
2798             pcmpgtw mm7, mm5       // pa > pb?
2799             movq mm0, mm7
2800             // use mm7 mask to merge pa & pb
2801             pand mm5, mm7
2802             // use mm0 mask copy to merge a & b
2803             pand mm2, mm0
2804             pandn mm7, mm4
2805             pandn mm0, mm1
2806             paddw mm7, mm5
2807             paddw mm0, mm2
2808             //  test  ((pa <= pb)? pa:pb) <= pc
2809             pcmpgtw mm7, mm6           // pab > pc?
2810             pxor mm1, mm1
2811             pand mm3, mm7
2812             pandn mm7, mm0
2813             pxor mm1, mm1
2814             paddw mm7, mm3
2815             pxor mm0, mm0
2816             // Step ex to next set of 8 bytes and repeat loop til done
2817             add ebx, 8
2818             packuswb mm1, mm7
2819             paddb mm1, [edi + ebx - 8]     // add Paeth predictor with Raw(x)
2820             cmp ebx, MMXLength
2821             movq [edi + ebx - 8], mm1      // write back updated value
2822                                 // mm1 will be used as Raw(x-bpp) next loop
2823             jb dpth6lp
2824          } // end _asm block
2825       }
2826       break;
2827
2828       case 4:
2829       {
2830          ActiveMask.use  = 0x00000000ffffffff;
2831          _asm {
2832             mov ebx, diff
2833             mov edi, row
2834             mov esi, prev_row
2835             pxor mm0, mm0
2836             // PRIME the pump (load the first Raw(x-bpp) data set
2837             movq mm1, [edi+ebx-8]    // Only time should need to read
2838                                      //  a=Raw(x-bpp) bytes
2839 dpth4lp:
2840             // Do first set of 4 bytes
2841             movq mm3, [esi+ebx-8]    // read c=Prior(x-bpp) bytes
2842             punpckhbw mm1, mm0       // Unpack Low bytes of a
2843             movq mm2, [esi + ebx]    // load b=Prior(x)
2844             punpcklbw mm2, mm0       // Unpack High bytes of b
2845             // pav = p - a = (a + b - c) - a = b - c
2846             movq mm4, mm2
2847             punpckhbw mm3, mm0       // Unpack High bytes of c
2848             // pbv = p - b = (a + b - c) - b = a - c
2849             movq mm5, mm1
2850             psubw mm4, mm3
2851             pxor mm7, mm7
2852             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
2853             movq mm6, mm4
2854             psubw mm5, mm3
2855             // pa = abs(p-a) = abs(pav)
2856             // pb = abs(p-b) = abs(pbv)
2857             // pc = abs(p-c) = abs(pcv)
2858             pcmpgtw mm0, mm4       // Create mask pav bytes < 0
2859             paddw mm6, mm5
2860             pand mm0, mm4          // Only pav bytes < 0 in mm7
2861             pcmpgtw mm7, mm5       // Create mask pbv bytes < 0
2862             psubw mm4, mm0
2863             pand mm7, mm5          // Only pbv bytes < 0 in mm0
2864             psubw mm4, mm0
2865             psubw mm5, mm7
2866             pxor mm0, mm0
2867             pcmpgtw mm0, mm6       // Create mask pcv bytes < 0
2868             pand mm0, mm6          // Only pav bytes < 0 in mm7
2869             psubw mm5, mm7
2870             psubw mm6, mm0
2871             //  test pa <= pb
2872             movq mm7, mm4
2873             psubw mm6, mm0
2874             pcmpgtw mm7, mm5       // pa > pb?
2875             movq mm0, mm7
2876             // use mm7 mask to merge pa & pb
2877             pand mm5, mm7
2878             // use mm0 mask copy to merge a & b
2879             pand mm2, mm0
2880             pandn mm7, mm4
2881             pandn mm0, mm1
2882             paddw mm7, mm5
2883             paddw mm0, mm2
2884             //  test  ((pa <= pb)? pa:pb) <= pc
2885             pcmpgtw mm7, mm6       // pab > pc?
2886             pxor mm1, mm1
2887             pand mm3, mm7
2888             pandn mm7, mm0
2889             paddw mm7, mm3
2890             pxor mm0, mm0
2891             packuswb mm7, mm1
2892             movq mm3, [esi + ebx]      // load c=Prior(x-bpp)
2893             pand mm7, ActiveMask
2894             movq mm2, mm3              // load b=Prior(x) step 1
2895             paddb mm7, [edi + ebx]     // add Paeth predictor with Raw(x)
2896             punpcklbw mm3, mm0         // Unpack High bytes of c
2897             movq [edi + ebx], mm7      // write back updated value
2898             movq mm1, mm7              // Now mm1 will be used as Raw(x-bpp)
2899             // Do second set of 4 bytes
2900             punpckhbw mm2, mm0         // Unpack Low bytes of b
2901             punpcklbw mm1, mm0         // Unpack Low bytes of a
2902             // pav = p - a = (a + b - c) - a = b - c
2903             movq mm4, mm2
2904             // pbv = p - b = (a + b - c) - b = a - c
2905             movq mm5, mm1
2906             psubw mm4, mm3
2907             pxor mm7, mm7
2908             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
2909             movq mm6, mm4
2910             psubw mm5, mm3
2911             // pa = abs(p-a) = abs(pav)
2912             // pb = abs(p-b) = abs(pbv)
2913             // pc = abs(p-c) = abs(pcv)
2914             pcmpgtw mm0, mm4       // Create mask pav bytes < 0
2915             paddw mm6, mm5
2916             pand mm0, mm4          // Only pav bytes < 0 in mm7
2917             pcmpgtw mm7, mm5       // Create mask pbv bytes < 0
2918             psubw mm4, mm0
2919             pand mm7, mm5          // Only pbv bytes < 0 in mm0
2920             psubw mm4, mm0
2921             psubw mm5, mm7
2922             pxor mm0, mm0
2923             pcmpgtw mm0, mm6       // Create mask pcv bytes < 0
2924             pand mm0, mm6          // Only pav bytes < 0 in mm7
2925             psubw mm5, mm7
2926             psubw mm6, mm0
2927             //  test pa <= pb
2928             movq mm7, mm4
2929             psubw mm6, mm0
2930             pcmpgtw mm7, mm5       // pa > pb?
2931             movq mm0, mm7
2932             // use mm7 mask to merge pa & pb
2933             pand mm5, mm7
2934             // use mm0 mask copy to merge a & b
2935             pand mm2, mm0
2936             pandn mm7, mm4
2937             pandn mm0, mm1
2938             paddw mm7, mm5
2939             paddw mm0, mm2
2940             //  test  ((pa <= pb)? pa:pb) <= pc
2941             pcmpgtw mm7, mm6       // pab > pc?
2942             pxor mm1, mm1
2943             pand mm3, mm7
2944             pandn mm7, mm0
2945             pxor mm1, mm1
2946             paddw mm7, mm3
2947             pxor mm0, mm0
2948             // Step ex to next set of 8 bytes and repeat loop til done
2949             add ebx, 8
2950             packuswb mm1, mm7
2951             paddb mm1, [edi + ebx - 8]     // add Paeth predictor with Raw(x)
2952             cmp ebx, MMXLength
2953             movq [edi + ebx - 8], mm1      // write back updated value
2954                                 // mm1 will be used as Raw(x-bpp) next loop
2955             jb dpth4lp
2956          } // end _asm block
2957       }
2958       break;
2959       case 8:                          // bpp == 8
2960       {
2961          ActiveMask.use  = 0x00000000ffffffff;
2962          _asm {
2963             mov ebx, diff
2964             mov edi, row
2965             mov esi, prev_row
2966             pxor mm0, mm0
2967             // PRIME the pump (load the first Raw(x-bpp) data set
2968             movq mm1, [edi+ebx-8]      // Only time should need to read
2969                                        //  a=Raw(x-bpp) bytes
2970 dpth8lp:
2971             // Do first set of 4 bytes
2972             movq mm3, [esi+ebx-8]      // read c=Prior(x-bpp) bytes
2973             punpcklbw mm1, mm0         // Unpack Low bytes of a
2974             movq mm2, [esi + ebx]      // load b=Prior(x)
2975             punpcklbw mm2, mm0         // Unpack Low bytes of b
2976             // pav = p - a = (a + b - c) - a = b - c
2977             movq mm4, mm2
2978             punpcklbw mm3, mm0         // Unpack Low bytes of c
2979             // pbv = p - b = (a + b - c) - b = a - c
2980             movq mm5, mm1
2981             psubw mm4, mm3
2982             pxor mm7, mm7
2983             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
2984             movq mm6, mm4
2985             psubw mm5, mm3
2986             // pa = abs(p-a) = abs(pav)
2987             // pb = abs(p-b) = abs(pbv)
2988             // pc = abs(p-c) = abs(pcv)
2989             pcmpgtw mm0, mm4       // Create mask pav bytes < 0
2990             paddw mm6, mm5
2991             pand mm0, mm4          // Only pav bytes < 0 in mm7
2992             pcmpgtw mm7, mm5       // Create mask pbv bytes < 0
2993             psubw mm4, mm0
2994             pand mm7, mm5          // Only pbv bytes < 0 in mm0
2995             psubw mm4, mm0
2996             psubw mm5, mm7
2997             pxor mm0, mm0
2998             pcmpgtw mm0, mm6       // Create mask pcv bytes < 0
2999             pand mm0, mm6          // Only pav bytes < 0 in mm7
3000             psubw mm5, mm7
3001             psubw mm6, mm0
3002             //  test pa <= pb
3003             movq mm7, mm4
3004             psubw mm6, mm0
3005             pcmpgtw mm7, mm5       // pa > pb?
3006             movq mm0, mm7
3007             // use mm7 mask to merge pa & pb
3008             pand mm5, mm7
3009             // use mm0 mask copy to merge a & b
3010             pand mm2, mm0
3011             pandn mm7, mm4
3012             pandn mm0, mm1
3013             paddw mm7, mm5
3014             paddw mm0, mm2
3015             //  test  ((pa <= pb)? pa:pb) <= pc
3016             pcmpgtw mm7, mm6       // pab > pc?
3017             pxor mm1, mm1
3018             pand mm3, mm7
3019             pandn mm7, mm0
3020             paddw mm7, mm3
3021             pxor mm0, mm0
3022             packuswb mm7, mm1
3023             movq mm3, [esi+ebx-8]    // read c=Prior(x-bpp) bytes
3024             pand mm7, ActiveMask
3025             movq mm2, [esi + ebx]    // load b=Prior(x)
3026             paddb mm7, [edi + ebx]   // add Paeth predictor with Raw(x)
3027             punpckhbw mm3, mm0       // Unpack High bytes of c
3028             movq [edi + ebx], mm7    // write back updated value
3029             movq mm1, [edi+ebx-8]    // read a=Raw(x-bpp) bytes
3030
3031             // Do second set of 4 bytes
3032             punpckhbw mm2, mm0       // Unpack High bytes of b
3033             punpckhbw mm1, mm0       // Unpack High bytes of a
3034             // pav = p - a = (a + b - c) - a = b - c
3035             movq mm4, mm2
3036             // pbv = p - b = (a + b - c) - b = a - c
3037             movq mm5, mm1
3038             psubw mm4, mm3
3039             pxor mm7, mm7
3040             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
3041             movq mm6, mm4
3042             psubw mm5, mm3
3043             // pa = abs(p-a) = abs(pav)
3044             // pb = abs(p-b) = abs(pbv)
3045             // pc = abs(p-c) = abs(pcv)
3046             pcmpgtw mm0, mm4       // Create mask pav bytes < 0
3047             paddw mm6, mm5
3048             pand mm0, mm4          // Only pav bytes < 0 in mm7
3049             pcmpgtw mm7, mm5       // Create mask pbv bytes < 0
3050             psubw mm4, mm0
3051             pand mm7, mm5          // Only pbv bytes < 0 in mm0
3052             psubw mm4, mm0
3053             psubw mm5, mm7
3054             pxor mm0, mm0
3055             pcmpgtw mm0, mm6       // Create mask pcv bytes < 0
3056             pand mm0, mm6          // Only pav bytes < 0 in mm7
3057             psubw mm5, mm7
3058             psubw mm6, mm0
3059             //  test pa <= pb
3060             movq mm7, mm4
3061             psubw mm6, mm0
3062             pcmpgtw mm7, mm5       // pa > pb?
3063             movq mm0, mm7
3064             // use mm7 mask to merge pa & pb
3065             pand mm5, mm7
3066             // use mm0 mask copy to merge a & b
3067             pand mm2, mm0
3068             pandn mm7, mm4
3069             pandn mm0, mm1
3070             paddw mm7, mm5
3071             paddw mm0, mm2
3072             //  test  ((pa <= pb)? pa:pb) <= pc
3073             pcmpgtw mm7, mm6       // pab > pc?
3074             pxor mm1, mm1
3075             pand mm3, mm7
3076             pandn mm7, mm0
3077             pxor mm1, mm1
3078             paddw mm7, mm3
3079             pxor mm0, mm0
3080             // Step ex to next set of 8 bytes and repeat loop til done
3081             add ebx, 8
3082             packuswb mm1, mm7
3083             paddb mm1, [edi + ebx - 8]     // add Paeth predictor with Raw(x)
3084             cmp ebx, MMXLength
3085             movq [edi + ebx - 8], mm1      // write back updated value
3086                             // mm1 will be used as Raw(x-bpp) next loop
3087             jb dpth8lp
3088          } // end _asm block
3089       }
3090       break;
3091
3092       case 1:                // bpp = 1
3093       case 2:                // bpp = 2
3094       default:               // bpp > 8
3095       {
3096          _asm {
3097             mov ebx, diff
3098             cmp ebx, FullLength
3099             jnb dpthdend
3100             mov edi, row
3101             mov esi, prev_row
3102             // Do Paeth decode for remaining bytes
3103             mov edx, ebx
3104             xor ecx, ecx        // zero ecx before using cl & cx in loop below
3105             sub edx, bpp        // Set edx = ebx - bpp
3106 dpthdlp:
3107             xor eax, eax
3108             // pav = p - a = (a + b - c) - a = b - c
3109             mov al, [esi + ebx]        // load Prior(x) into al
3110             mov cl, [esi + edx]        // load Prior(x-bpp) into cl
3111             sub eax, ecx                 // subtract Prior(x-bpp)
3112             mov patemp, eax                 // Save pav for later use
3113             xor eax, eax
3114             // pbv = p - b = (a + b - c) - b = a - c
3115             mov al, [edi + edx]        // load Raw(x-bpp) into al
3116             sub eax, ecx                 // subtract Prior(x-bpp)
3117             mov ecx, eax
3118             // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
3119             add eax, patemp                 // pcv = pav + pbv
3120             // pc = abs(pcv)
3121             test eax, 0x80000000
3122             jz dpthdpca
3123             neg eax                     // reverse sign of neg values
3124 dpthdpca:
3125             mov pctemp, eax             // save pc for later use
3126             // pb = abs(pbv)
3127             test ecx, 0x80000000
3128             jz dpthdpba
3129             neg ecx                     // reverse sign of neg values
3130 dpthdpba:
3131             mov pbtemp, ecx             // save pb for later use
3132             // pa = abs(pav)
3133             mov eax, patemp
3134             test eax, 0x80000000
3135             jz dpthdpaa
3136             neg eax                     // reverse sign of neg values
3137 dpthdpaa:
3138             mov patemp, eax             // save pa for later use
3139             // test if pa <= pb
3140             cmp eax, ecx
3141             jna dpthdabb
3142             // pa > pb; now test if pb <= pc
3143             cmp ecx, pctemp
3144             jna dpthdbbc
3145             // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
3146             mov cl, [esi + edx]  // load Prior(x-bpp) into cl
3147             jmp dpthdpaeth
3148 dpthdbbc:
3149             // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
3150             mov cl, [esi + ebx]        // load Prior(x) into cl
3151             jmp dpthdpaeth
3152 dpthdabb:
3153             // pa <= pb; now test if pa <= pc
3154             cmp eax, pctemp
3155             jna dpthdabc
3156             // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
3157             mov cl, [esi + edx]  // load Prior(x-bpp) into cl
3158             jmp dpthdpaeth
3159 dpthdabc:
3160             // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
3161             mov cl, [edi + edx]  // load Raw(x-bpp) into cl
3162 dpthdpaeth:
3163             inc ebx
3164             inc edx
3165             // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
3166             add [edi + ebx - 1], cl
3167             cmp ebx, FullLength
3168             jb dpthdlp
3169 dpthdend:
3170          } // end _asm block
3171       }
3172       return;                   // No need to go further with this one
3173    }                         // end switch ( bpp )
3174    _asm
3175    {
3176          // MMX acceleration complete now do clean-up
3177          // Check if any remaining bytes left to decode
3178          mov ebx, MMXLength
3179          cmp ebx, FullLength
3180          jnb dpthend
3181          mov edi, row
3182          mov esi, prev_row
3183          // Do Paeth decode for remaining bytes
3184          mov edx, ebx
3185          xor ecx, ecx         // zero ecx before using cl & cx in loop below
3186          sub edx, bpp         // Set edx = ebx - bpp
3187 dpthlp2:
3188          xor eax, eax
3189          // pav = p - a = (a + b - c) - a = b - c
3190          mov al, [esi + ebx]  // load Prior(x) into al
3191          mov cl, [esi + edx]  // load Prior(x-bpp) into cl
3192          sub eax, ecx         // subtract Prior(x-bpp)
3193          mov patemp, eax      // Save pav for later use
3194          xor eax, eax
3195          // pbv = p - b = (a + b - c) - b = a - c
3196          mov al, [edi + edx]  // load Raw(x-bpp) into al
3197          sub eax, ecx         // subtract Prior(x-bpp)
3198          mov ecx, eax
3199          // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
3200          add eax, patemp      // pcv = pav + pbv
3201          // pc = abs(pcv)
3202          test eax, 0x80000000
3203          jz dpthpca2
3204          neg eax              // reverse sign of neg values
3205 dpthpca2:
3206          mov pctemp, eax      // save pc for later use
3207          // pb = abs(pbv)
3208          test ecx, 0x80000000
3209          jz dpthpba2
3210          neg ecx              // reverse sign of neg values
3211 dpthpba2:
3212          mov pbtemp, ecx      // save pb for later use
3213          // pa = abs(pav)
3214          mov eax, patemp
3215          test eax, 0x80000000
3216          jz dpthpaa2
3217          neg eax              // reverse sign of neg values
3218 dpthpaa2:
3219          mov patemp, eax      // save pa for later use
3220          // test if pa <= pb
3221          cmp eax, ecx
3222          jna dpthabb2
3223          // pa > pb; now test if pb <= pc
3224          cmp ecx, pctemp
3225          jna dpthbbc2
3226          // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
3227          mov cl, [esi + edx]  // load Prior(x-bpp) into cl
3228          jmp dpthpaeth2
3229 dpthbbc2:
3230          // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
3231          mov cl, [esi + ebx]        // load Prior(x) into cl
3232          jmp dpthpaeth2
3233 dpthabb2:
3234          // pa <= pb; now test if pa <= pc
3235          cmp eax, pctemp
3236          jna dpthabc2
3237          // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
3238          mov cl, [esi + edx]  // load Prior(x-bpp) into cl
3239          jmp dpthpaeth2
3240 dpthabc2:
3241          // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
3242          mov cl, [edi + edx]  // load Raw(x-bpp) into cl
3243 dpthpaeth2:
3244          inc ebx
3245          inc edx
3246          // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
3247          add [edi + ebx - 1], cl
3248          cmp ebx, FullLength
3249          jb dpthlp2
3250 dpthend:
3251          emms             // End MMX instructions; prep for possible FP instrs.
3252    } // end _asm block
3253 }
3254
3255 // Optimized code for PNG Sub filter decoder
3256 void /* PRIVATE */
3257 png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row)
3258 {
3259    //int test;
3260    int bpp;
3261    png_uint_32 FullLength;
3262    png_uint_32 MMXLength;
3263    int diff;
3264
3265    bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
3266    FullLength  = row_info->rowbytes - bpp; // # of bytes to filter
3267    _asm {
3268         mov edi, row
3269         mov esi, edi               // lp = row
3270         add edi, bpp               // rp = row + bpp
3271         xor eax, eax
3272         // get # of bytes to alignment
3273         mov diff, edi               // take start of row
3274         add diff, 0xf               // add 7 + 8 to incr past
3275                                         // alignment boundary
3276         xor ebx, ebx
3277         and diff, 0xfffffff8        // mask to alignment boundary
3278         sub diff, edi               // subtract from start ==> value
3279                                         //  ebx at alignment
3280         jz dsubgo
3281         // fix alignment
3282 dsublp1:
3283         mov al, [esi+ebx]
3284         add [edi+ebx], al
3285         inc ebx
3286         cmp ebx, diff
3287         jb dsublp1
3288 dsubgo:
3289         mov ecx, FullLength
3290         mov edx, ecx
3291         sub edx, ebx                  // subtract alignment fix
3292         and edx, 0x00000007           // calc bytes over mult of 8
3293         sub ecx, edx                  // drop over bytes from length
3294         mov MMXLength, ecx
3295    } // end _asm block
3296
3297    // Now do the math for the rest of the row
3298    switch ( bpp )
3299    {
3300         case 3:
3301         {
3302          ActiveMask.use  = 0x0000ffffff000000;
3303          ShiftBpp.use = 24;       // == 3 * 8
3304          ShiftRem.use  = 40;      // == 64 - 24
3305          _asm {
3306             mov edi, row
3307             movq mm7, ActiveMask  // Load ActiveMask for 2nd active byte group
3308             mov esi, edi              // lp = row
3309             add edi, bpp          // rp = row + bpp
3310             movq mm6, mm7
3311             mov ebx, diff
3312             psllq mm6, ShiftBpp   // Move mask in mm6 to cover 3rd active
3313                                   // byte group
3314             // PRIME the pump (load the first Raw(x-bpp) data set
3315             movq mm1, [edi+ebx-8]
3316 dsub3lp:
3317             psrlq mm1, ShiftRem   // Shift data for adding 1st bpp bytes
3318                           // no need for mask; shift clears inactive bytes
3319             // Add 1st active group
3320             movq mm0, [edi+ebx]
3321             paddb mm0, mm1
3322             // Add 2nd active group
3323             movq mm1, mm0         // mov updated Raws to mm1
3324             psllq mm1, ShiftBpp   // shift data to position correctly
3325             pand mm1, mm7         // mask to use only 2nd active group
3326             paddb mm0, mm1
3327             // Add 3rd active group
3328             movq mm1, mm0         // mov updated Raws to mm1
3329             psllq mm1, ShiftBpp   // shift data to position correctly
3330             pand mm1, mm6         // mask to use only 3rd active group
3331             add ebx, 8
3332             paddb mm0, mm1
3333             cmp ebx, MMXLength
3334             movq [edi+ebx-8], mm0     // Write updated Raws back to array
3335             // Prep for doing 1st add at top of loop
3336             movq mm1, mm0
3337             jb dsub3lp
3338          } // end _asm block
3339       }
3340       break;
3341
3342       case 1:
3343       {
3344          // Placed here just in case this is a duplicate of the
3345          // non-MMX code for the SUB filter in png_read_filter_row below
3346          //
3347          //         png_bytep rp;
3348          //         png_bytep lp;
3349          //         png_uint_32 i;
3350          //         bpp = (row_info->pixel_depth + 7) >> 3;
3351          //         for (i = (png_uint_32)bpp, rp = row + bpp, lp = row;
3352          //            i < row_info->rowbytes; i++, rp++, lp++)
3353          //      {
3354          //            *rp = (png_byte)(((int)(*rp) + (int)(*lp)) & 0xff);
3355          //      }
3356          _asm {
3357             mov ebx, diff
3358             mov edi, row
3359             cmp ebx, FullLength
3360             jnb dsub1end
3361             mov esi, edi          // lp = row
3362             xor eax, eax
3363             add edi, bpp      // rp = row + bpp
3364 dsub1lp:
3365             mov al, [esi+ebx]
3366             add [edi+ebx], al
3367             inc ebx
3368             cmp ebx, FullLength
3369             jb dsub1lp
3370 dsub1end:
3371          } // end _asm block
3372       }
3373       return;
3374
3375       case 6:
3376       case 7:
3377       case 4:
3378       case 5:
3379       {
3380          ShiftBpp.use = bpp << 3;
3381          ShiftRem.use = 64 - ShiftBpp.use;
3382          _asm {
3383             mov edi, row
3384             mov ebx, diff
3385             mov esi, edi               // lp = row
3386             add edi, bpp           // rp = row + bpp
3387             // PRIME the pump (load the first Raw(x-bpp) data set
3388             movq mm1, [edi+ebx-8]
3389 dsub4lp:
3390             psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes
3391                           // no need for mask; shift clears inactive bytes
3392             movq mm0, [edi+ebx]
3393             paddb mm0, mm1
3394             // Add 2nd active group
3395             movq mm1, mm0          // mov updated Raws to mm1
3396             psllq mm1, ShiftBpp    // shift data to position correctly
3397                                    // there is no need for any mask
3398                                    // since shift clears inactive bits/bytes
3399             add ebx, 8
3400             paddb mm0, mm1
3401             cmp ebx, MMXLength
3402             movq [edi+ebx-8], mm0
3403             movq mm1, mm0          // Prep for doing 1st add at top of loop
3404             jb dsub4lp
3405          } // end _asm block
3406       }
3407       break;
3408
3409       case 2:
3410       {
3411          ActiveMask.use  = 0x00000000ffff0000;
3412          ShiftBpp.use = 16;       // == 2 * 8
3413          ShiftRem.use = 48;       // == 64 - 16
3414          _asm {
3415             movq mm7, ActiveMask  // Load ActiveMask for 2nd active byte group
3416             mov ebx, diff
3417             movq mm6, mm7
3418             mov edi, row
3419             psllq mm6, ShiftBpp     // Move mask in mm6 to cover 3rd active
3420                                     //  byte group
3421             mov esi, edi            // lp = row
3422             movq mm5, mm6
3423             add edi, bpp            // rp = row + bpp
3424             psllq mm5, ShiftBpp     // Move mask in mm5 to cover 4th active
3425                                     //  byte group
3426             // PRIME the pump (load the first Raw(x-bpp) data set
3427             movq mm1, [edi+ebx-8]
3428 dsub2lp:
3429             // Add 1st active group
3430             psrlq mm1, ShiftRem     // Shift data for adding 1st bpp bytes
3431                                     // no need for mask; shift clears inactive
3432                                     //  bytes
3433             movq mm0, [edi+ebx]
3434             paddb mm0, mm1
3435             // Add 2nd active group
3436             movq mm1, mm0           // mov updated Raws to mm1
3437             psllq mm1, ShiftBpp     // shift data to position correctly
3438             pand mm1, mm7           // mask to use only 2nd active group
3439             paddb mm0, mm1
3440             // Add 3rd active group
3441             movq mm1, mm0           // mov updated Raws to mm1
3442             psllq mm1, ShiftBpp     // shift data to position correctly
3443             pand mm1, mm6           // mask to use only 3rd active group
3444             paddb mm0, mm1
3445             // Add 4th active group
3446             movq mm1, mm0           // mov updated Raws to mm1
3447             psllq mm1, ShiftBpp     // shift data to position correctly
3448             pand mm1, mm5           // mask to use only 4th active group
3449             add ebx, 8
3450             paddb mm0, mm1
3451             cmp ebx, MMXLength
3452             movq [edi+ebx-8], mm0   // Write updated Raws back to array
3453             movq mm1, mm0           // Prep for doing 1st add at top of loop
3454             jb dsub2lp
3455          } // end _asm block
3456       }
3457       break;
3458       case 8:
3459       {
3460          _asm {
3461             mov edi, row
3462             mov ebx, diff
3463             mov esi, edi            // lp = row
3464             add edi, bpp            // rp = row + bpp
3465             mov ecx, MMXLength
3466             movq mm7, [edi+ebx-8]   // PRIME the pump (load the first
3467                                     // Raw(x-bpp) data set
3468             and ecx, 0x0000003f     // calc bytes over mult of 64
3469 dsub8lp:
3470             movq mm0, [edi+ebx]     // Load Sub(x) for 1st 8 bytes
3471             paddb mm0, mm7
3472             movq mm1, [edi+ebx+8]   // Load Sub(x) for 2nd 8 bytes
3473             movq [edi+ebx], mm0    // Write Raw(x) for 1st 8 bytes
3474                                    // Now mm0 will be used as Raw(x-bpp) for
3475                                    // the 2nd group of 8 bytes.  This will be
3476                                    // repeated for each group of 8 bytes with
3477                                    // the 8th group being used as the Raw(x-bpp)
3478                                    // for the 1st group of the next loop.
3479             paddb mm1, mm0
3480             movq mm2, [edi+ebx+16]  // Load Sub(x) for 3rd 8 bytes
3481             movq [edi+ebx+8], mm1   // Write Raw(x) for 2nd 8 bytes
3482             paddb mm2, mm1
3483             movq mm3, [edi+ebx+24]  // Load Sub(x) for 4th 8 bytes
3484             movq [edi+ebx+16], mm2  // Write Raw(x) for 3rd 8 bytes
3485             paddb mm3, mm2
3486             movq mm4, [edi+ebx+32]  // Load Sub(x) for 5th 8 bytes
3487             movq [edi+ebx+24], mm3  // Write Raw(x) for 4th 8 bytes
3488             paddb mm4, mm3
3489             movq mm5, [edi+ebx+40]  // Load Sub(x) for 6th 8 bytes
3490             movq [edi+ebx+32], mm4  // Write Raw(x) for 5th 8 bytes
3491             paddb mm5, mm4
3492             movq mm6, [edi+ebx+48]  // Load Sub(x) for 7th 8 bytes
3493             movq [edi+ebx+40], mm5  // Write Raw(x) for 6th 8 bytes
3494             paddb mm6, mm5
3495             movq mm7, [edi+ebx+56]  // Load Sub(x) for 8th 8 bytes
3496             movq [edi+ebx+48], mm6  // Write Raw(x) for 7th 8 bytes
3497             add ebx, 64
3498             paddb mm7, mm6
3499             cmp ebx, ecx
3500             movq [edi+ebx-8], mm7   // Write Raw(x) for 8th 8 bytes
3501             jb dsub8lp
3502             cmp ebx, MMXLength
3503             jnb dsub8lt8
3504 dsub8lpA:
3505             movq mm0, [edi+ebx]
3506             add ebx, 8
3507             paddb mm0, mm7
3508             cmp ebx, MMXLength
3509             movq [edi+ebx-8], mm0   // use -8 to offset early add to ebx
3510             movq mm7, mm0           // Move calculated Raw(x) data to mm1 to
3511                                     // be the new Raw(x-bpp) for the next loop
3512             jb dsub8lpA
3513 dsub8lt8:
3514          } // end _asm block
3515       }
3516       break;
3517
3518       default:                // bpp greater than 8 bytes
3519       {
3520          _asm {
3521             mov ebx, diff
3522             mov edi, row
3523             mov esi, edi           // lp = row
3524             add edi, bpp           // rp = row + bpp
3525 dsubAlp:
3526             movq mm0, [edi+ebx]
3527             movq mm1, [esi+ebx]
3528             add ebx, 8
3529             paddb mm0, mm1
3530             cmp ebx, MMXLength
3531             movq [edi+ebx-8], mm0  // mov does not affect flags; -8 to offset
3532                                    //  add ebx
3533             jb dsubAlp
3534          } // end _asm block
3535       }
3536       break;
3537
3538    } // end switch ( bpp )
3539
3540    _asm {
3541         mov ebx, MMXLength
3542         mov edi, row
3543         cmp ebx, FullLength
3544         jnb dsubend
3545         mov esi, edi               // lp = row
3546         xor eax, eax
3547         add edi, bpp               // rp = row + bpp
3548 dsublp2:
3549         mov al, [esi+ebx]
3550         add [edi+ebx], al
3551         inc ebx
3552         cmp ebx, FullLength
3553         jb dsublp2
3554 dsubend:
3555         emms             // End MMX instructions; prep for possible FP instrs.
3556    } // end _asm block
3557 }
3558
3559 // Optimized code for PNG Up filter decoder
3560 void /* PRIVATE */
3561 png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row,
3562    png_bytep prev_row)
3563 {
3564    png_uint_32 len;
3565    len  = row_info->rowbytes;       // # of bytes to filter
3566    _asm {
3567       mov edi, row
3568       // get # of bytes to alignment
3569       mov ecx, edi
3570       xor ebx, ebx
3571       add ecx, 0x7
3572       xor eax, eax
3573       and ecx, 0xfffffff8
3574       mov esi, prev_row
3575       sub ecx, edi
3576       jz dupgo
3577       // fix alignment
3578 duplp1:
3579       mov al, [edi+ebx]
3580       add al, [esi+ebx]
3581       inc ebx
3582       cmp ebx, ecx
3583       mov [edi + ebx-1], al  // mov does not affect flags; -1 to offset inc ebx
3584       jb duplp1
3585 dupgo:
3586       mov ecx, len
3587       mov edx, ecx
3588       sub edx, ebx                  // subtract alignment fix
3589       and edx, 0x0000003f           // calc bytes over mult of 64
3590       sub ecx, edx                  // drop over bytes from length
3591       // Unrolled loop - use all MMX registers and interleave to reduce
3592       // number of branch instructions (loops) and reduce partial stalls
3593 duploop:
3594       movq mm1, [esi+ebx]
3595       movq mm0, [edi+ebx]
3596       movq mm3, [esi+ebx+8]
3597       paddb mm0, mm1
3598       movq mm2, [edi+ebx+8]
3599       movq [edi+ebx], mm0
3600       paddb mm2, mm3
3601       movq mm5, [esi+ebx+16]
3602       movq [edi+ebx+8], mm2
3603       movq mm4, [edi+ebx+16]
3604       movq mm7, [esi+ebx+24]
3605       paddb mm4, mm5
3606       movq mm6, [edi+ebx+24]
3607       movq [edi+ebx+16], mm4
3608       paddb mm6, mm7
3609       movq mm1, [esi+ebx+32]
3610       movq [edi+ebx+24], mm6
3611       movq mm0, [edi+ebx+32]
3612       movq mm3, [esi+ebx+40]
3613       paddb mm0, mm1
3614       movq mm2, [edi+ebx+40]
3615       movq [edi+ebx+32], mm0
3616       paddb mm2, mm3
3617       movq mm5, [esi+ebx+48]
3618       movq [edi+ebx+40], mm2
3619       movq mm4, [edi+ebx+48]
3620       movq mm7, [esi+ebx+56]
3621       paddb mm4, mm5
3622       movq mm6, [edi+ebx+56]
3623       movq [edi+ebx+48], mm4
3624       add ebx, 64
3625       paddb mm6, mm7
3626       cmp ebx, ecx
3627       movq [edi+ebx-8], mm6 // (+56)movq does not affect flags;
3628                                      // -8 to offset add ebx
3629       jb duploop
3630
3631       cmp edx, 0                     // Test for bytes over mult of 64
3632       jz dupend
3633
3634
3635       // 2 lines added by lcreeve at netins.net
3636       // (mail 11 Jul 98 in png-implement list)
3637       cmp edx, 8 //test for less than 8 bytes
3638       jb duplt8
3639
3640
3641       add ecx, edx
3642       and edx, 0x00000007           // calc bytes over mult of 8
3643       sub ecx, edx                  // drop over bytes from length
3644       jz duplt8
3645       // Loop using MMX registers mm0 & mm1 to update 8 bytes simultaneously
3646 duplpA:
3647       movq mm1, [esi+ebx]
3648       movq mm0, [edi+ebx]
3649       add ebx, 8
3650       paddb mm0, mm1
3651       cmp ebx, ecx
3652       movq [edi+ebx-8], mm0 // movq does not affect flags; -8 to offset add ebx
3653       jb duplpA
3654       cmp edx, 0            // Test for bytes over mult of 8
3655       jz dupend
3656 duplt8:
3657       xor eax, eax
3658       add ecx, edx          // move over byte count into counter
3659       // Loop using x86 registers to update remaining bytes
3660 duplp2:
3661       mov al, [edi + ebx]
3662       add al, [esi + ebx]
3663       inc ebx
3664       cmp ebx, ecx
3665       mov [edi + ebx-1], al // mov does not affect flags; -1 to offset inc ebx
3666       jb duplp2
3667 dupend:
3668       // Conversion of filtered row completed
3669       emms          // End MMX instructions; prep for possible FP instrs.
3670    } // end _asm block
3671 }
3672
3673
3674 // Optimized png_read_filter_row routines
3675 void /* PRIVATE */
3676 png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep
3677    row, png_bytep prev_row, int filter)
3678 {
3679 #ifdef PNG_DEBUG
3680    char filnm[10];
3681 #endif
3682
3683    if (mmx_supported == 2) {
3684 #if !defined(PNG_1_0_X)
3685        /* this should have happened in png_init_mmx_flags() already */
3686        png_warning(png_ptr, "asm_flags may not have been initialized");
3687 #endif
3688        png_mmx_support();
3689    }
3690
3691 #ifdef PNG_DEBUG
3692    png_debug(1, "in png_read_filter_row\n");
3693    switch (filter)
3694    {
3695       case 0: sprintf(filnm, "none");
3696          break;
3697 #if !defined(PNG_1_0_X)
3698       case 1: sprintf(filnm, "sub-%s",
3699         (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "MMX" : "x86");
3700          break;
3701       case 2: sprintf(filnm, "up-%s",
3702         (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP)? "MMX" : "x86");
3703          break;
3704       case 3: sprintf(filnm, "avg-%s",
3705         (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)? "MMX" : "x86");
3706          break;
3707       case 4: sprintf(filnm, "Paeth-%s",
3708         (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "MMX":"x86");
3709          break;
3710 #else
3711       case 1: sprintf(filnm, "sub");
3712          break;
3713       case 2: sprintf(filnm, "up");
3714          break;
3715       case 3: sprintf(filnm, "avg");
3716          break;
3717       case 4: sprintf(filnm, "Paeth");
3718          break;
3719 #endif
3720       default: sprintf(filnm, "unknw");
3721          break;
3722    }
3723    png_debug2(0,"row=%5d, %s, ", png_ptr->row_number, filnm);
3724    png_debug2(0, "pd=%2d, b=%d, ", (int)row_info->pixel_depth,
3725       (int)((row_info->pixel_depth + 7) >> 3));
3726    png_debug1(0,"len=%8d, ", row_info->rowbytes);
3727 #endif /* PNG_DEBUG */
3728
3729    switch (filter)
3730    {
3731       case PNG_FILTER_VALUE_NONE:
3732          break;
3733
3734       case PNG_FILTER_VALUE_SUB:
3735       {
3736 #if !defined(PNG_1_0_X)
3737          if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB) &&
3738              (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
3739              (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
3740 #else
3741          if (mmx_supported)
3742 #endif
3743          {
3744             png_read_filter_row_mmx_sub(row_info, row);
3745          }
3746          else
3747          {
3748             png_uint_32 i;
3749             png_uint_32 istop = row_info->rowbytes;
3750             png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
3751             png_bytep rp = row + bpp;
3752             png_bytep lp = row;
3753
3754             for (i = bpp; i < istop; i++)
3755             {
3756                *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
3757                rp++;
3758             }
3759          }
3760          break;
3761       }
3762
3763       case PNG_FILTER_VALUE_UP:
3764       {
3765 #if !defined(PNG_1_0_X)
3766          if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP) &&
3767              (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
3768              (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
3769 #else
3770          if (mmx_supported)
3771 #endif
3772          {
3773             png_read_filter_row_mmx_up(row_info, row, prev_row);
3774          }
3775          else
3776          {
3777             png_uint_32 i;
3778             png_uint_32 istop = row_info->rowbytes;
3779             png_bytep rp = row;
3780             png_bytep pp = prev_row;
3781
3782             for (i = 0; i < istop; ++i)
3783             {
3784                *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
3785                rp++;
3786             }
3787          }
3788          break;
3789       }
3790
3791       case PNG_FILTER_VALUE_AVG:
3792       {
3793 #if !defined(PNG_1_0_X)
3794          if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG) &&
3795              (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
3796              (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
3797 #else
3798          if (mmx_supported)
3799 #endif
3800          {
3801             png_read_filter_row_mmx_avg(row_info, row, prev_row);
3802          }
3803          else
3804          {
3805             png_uint_32 i;
3806             png_bytep rp = row;
3807             png_bytep pp = prev_row;
3808             png_bytep lp = row;
3809             png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
3810             png_uint_32 istop = row_info->rowbytes - bpp;
3811
3812             for (i = 0; i < bpp; i++)
3813             {
3814                *rp = (png_byte)(((int)(*rp) +
3815                   ((int)(*pp++) >> 1)) & 0xff);
3816                rp++;
3817             }
3818
3819             for (i = 0; i < istop; i++)
3820             {
3821                *rp = (png_byte)(((int)(*rp) +
3822                   ((int)(*pp++ + *lp++) >> 1)) & 0xff);
3823                rp++;
3824             }
3825          }
3826          break;
3827       }
3828
3829       case PNG_FILTER_VALUE_PAETH:
3830       {
3831 #if !defined(PNG_1_0_X)
3832          if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH) &&
3833              (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
3834              (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
3835 #else
3836          if (mmx_supported)
3837 #endif
3838          {
3839             png_read_filter_row_mmx_paeth(row_info, row, prev_row);
3840          }
3841          else
3842          {
3843             png_uint_32 i;
3844             png_bytep rp = row;
3845             png_bytep pp = prev_row;
3846             png_bytep lp = row;
3847             png_bytep cp = prev_row;
3848             png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
3849             png_uint_32 istop=row_info->rowbytes - bpp;
3850
3851             for (i = 0; i < bpp; i++)
3852             {
3853                *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
3854                rp++;
3855             }
3856
3857             for (i = 0; i < istop; i++)   // use leftover rp,pp
3858             {
3859                int a, b, c, pa, pb, pc, p;
3860
3861                a = *lp++;
3862                b = *pp++;
3863                c = *cp++;
3864
3865                p = b - c;
3866                pc = a - c;
3867
3868 #ifdef PNG_USE_ABS
3869                pa = abs(p);
3870                pb = abs(pc);
3871                pc = abs(p + pc);
3872 #else
3873                pa = p < 0 ? -p : p;
3874                pb = pc < 0 ? -pc : pc;
3875                pc = (p + pc) < 0 ? -(p + pc) : p + pc;
3876 #endif
3877
3878                /*
3879                   if (pa <= pb && pa <= pc)
3880                      p = a;
3881                   else if (pb <= pc)
3882                      p = b;
3883                   else
3884                      p = c;
3885                 */
3886
3887                p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
3888
3889                *rp = (png_byte)(((int)(*rp) + p) & 0xff);
3890                rp++;
3891             }
3892          }
3893          break;
3894       }
3895
3896       default:
3897          png_warning(png_ptr, "Ignoring bad row filter type");
3898          *row=0;
3899          break;
3900    }
3901 }
3902
3903 #endif /* PNG_ASSEMBLER_CODE_SUPPORTED && PNG_USE_PNGVCRD */