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