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