home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / Kasumi / source / blt_reference_yuv.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  42.9 KB  |  1,591 lines

  1. #include <vd2/system/vdtypes.h>
  2. #include <vd2/system/vdstl.h>
  3. #include <vd2/system/cpuaccel.h>
  4. #include <vd2/system/memory.h>
  5. #include <vd2/Kasumi/pixmap.h>
  6. #include <vd2/Kasumi/pixmaputils.h>
  7.  
  8. #include "blt_spanutils.h"
  9.  
  10. #ifdef _M_IX86
  11.     #include "blt_spanutils_x86.h"
  12. #endif
  13.  
  14. using namespace nsVDPixmapSpanUtils;
  15.  
  16. namespace {
  17.     struct YCbCrToRGB {
  18.         sint16 y_tab[256];
  19.         sint16 r_cr_tab[256];
  20.         sint16 b_cb_tab[256];
  21.         sint16 g_cr_tab[256];
  22.         sint16 g_cb_tab[256];
  23.         uint8 cliptab[277+256+279];
  24.         uint16 cliptab15[277+256+279];
  25.         uint16 cliptab16[277+256+279];
  26.  
  27.         YCbCrToRGB() {
  28.             int i;
  29.  
  30.             memset(cliptab, 0, 277);
  31.             memset(cliptab+277+256, 255, 279);
  32.  
  33.             memset(cliptab15, 0, sizeof cliptab15[0] * 277);
  34.             memset(cliptab16, 0, sizeof cliptab16[0] * 277);
  35.             memset(cliptab15+277+256, 0xff, sizeof cliptab15[0] * 279);
  36.             memset(cliptab16+277+256, 0xff, sizeof cliptab16[0] * 279);
  37.  
  38.             for(i=0; i<256; ++i) {
  39.                 y_tab[i] = (sint16)(((i-16) * 76309 + 32768) >> 16);
  40.                 r_cr_tab[i] = (sint16)(((i-128) * 104597 + 32768) >> 16);
  41.                 b_cb_tab[i] = (sint16)(((i-128) * 132201 + 32768) >> 16);
  42.                 g_cr_tab[i] = (sint16)(((i-128) * -53279 + 32768) >> 16);
  43.                 g_cb_tab[i] = (sint16)(((i-128) * -25674 + 32768) >> 16);
  44.                 cliptab[i+277] = (uint8)i;
  45.                 cliptab15[i+277] = 0x421 * ((unsigned)i>>3);
  46.                 cliptab16[i+277] = 0x801 * ((unsigned)i>>3) + 0x20 * ((unsigned)i>>2);
  47.             }
  48.         }
  49.     } colorconv;
  50.  
  51.     struct YCbCrFormatInfo {
  52.         ptrdiff_t    ystep;
  53.         ptrdiff_t    cstep;
  54.         ptrdiff_t    yinc[4];
  55.         ptrdiff_t    cinc[4];
  56.         sint8        ypos[4];
  57.         sint8        cbpos[4];
  58.         sint8        crpos[4];
  59.     };
  60.  
  61.     YCbCrFormatInfo        g_formatInfo_YUV444_Planar    = { -4, -4, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,1,2,3}, {0,1,2,3}, {0,1,2,3}};
  62.     YCbCrFormatInfo        g_formatInfo_YUV422_YUYV    = { -8, -8, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,2,4,6}, {1,1,5,5}, {3,3,7,7}};
  63.     YCbCrFormatInfo        g_formatInfo_YUV422_UYVY    = { -8, -8, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {1,3,5,7}, {0,0,4,4}, {2,2,6,6}};
  64.     YCbCrFormatInfo        g_formatInfo_YUV420_YV12    = { -4, -2, {-1,-1,-1,-1}, { 0,-1, 0,-1}, {0,1,2,3}, {0,0,1,1}, {0,0,1,1}};
  65.     YCbCrFormatInfo        g_formatInfo_YUV411_YV12    = { -4, -1, {-1,-1,-1,-1}, {-1,-1,-1,-1}, {0,1,2,3}, {0,0,0,0}, {0,0,0,0}};
  66.  
  67.     inline uint16 ycbcr_to_1555(uint8 y, uint8 cb0, uint8 cr0) {
  68.         const uint16 *p = &colorconv.cliptab15[277 + colorconv.y_tab[y]];
  69.         uint32 r = 0x7c00 & p[colorconv.r_cr_tab[cr0]];
  70.         uint32 g = 0x03e0 & p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]];
  71.         uint32 b = 0x001f & p[colorconv.b_cb_tab[cb0]];
  72.  
  73.         return r + g + b;
  74.     }
  75.  
  76.     inline uint16 ycbcr_to_565(uint8 y, uint8 cb0, uint8 cr0) {
  77.         const uint16 *p = &colorconv.cliptab16[277 + colorconv.y_tab[y]];
  78.         uint32 r = 0xf800 & p[colorconv.r_cr_tab[cr0]];
  79.         uint32 g = 0x07e0 & p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]];
  80.         uint32 b = 0x001f & p[colorconv.b_cb_tab[cb0]];
  81.  
  82.         return r + g + b;
  83.     }
  84.  
  85.     inline void ycbcr_to_888(uint8 *dst, uint8 y, uint8 cb0, uint8 cr0) {
  86.         const uint8 *p = &colorconv.cliptab[277 + colorconv.y_tab[y]];
  87.         uint8 r = p[colorconv.r_cr_tab[cr0]];
  88.         uint8 g = p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]];
  89.         uint8 b = p[colorconv.b_cb_tab[cb0]];
  90.  
  91.         dst[0] = b;
  92.         dst[1] = g;
  93.         dst[2] = r;
  94.     }
  95.  
  96.     inline uint32 ycbcr_to_8888(uint8 y, uint8 cb0, uint8 cr0) {
  97.         const uint8 *p = &colorconv.cliptab[277 + colorconv.y_tab[y]];
  98.         uint8 r = p[colorconv.r_cr_tab[cr0]];
  99.         uint8 g = p[colorconv.g_cr_tab[cr0] + colorconv.g_cb_tab[cb0]];
  100.         uint8 b = p[colorconv.b_cb_tab[cb0]];
  101.  
  102.         return (r << 16) + (g << 8) + b;
  103.     }
  104.  
  105.     void VDYCbCrToXRGB1555Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) {
  106.         uint16 *dst = (uint16 *)dst0;
  107.  
  108.         do {
  109.             *dst++ = ycbcr_to_1555(*y++, *cb++, *cr++);
  110.         } while(--w);
  111.     }
  112.  
  113.     void VDYCbCrToRGB565Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) {
  114.         uint16 *dst = (uint16 *)dst0;
  115.  
  116.         do {
  117.             *dst++ = ycbcr_to_565(*y++, *cb++, *cr++);
  118.         } while(--w);
  119.     }
  120.  
  121.     void VDYCbCrToRGB888Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) {
  122.         uint8 *dst = (uint8 *)dst0;
  123.  
  124.         do {
  125.             ycbcr_to_888(dst, *y++, *cb++, *cr++);
  126.             dst += 3;
  127.         } while(--w);
  128.     }
  129.  
  130.     void VDYCbCrToXRGB8888Span(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) {
  131.         uint32 *dst = (uint32 *)dst0;
  132.  
  133.         do {
  134.             *dst++ = ycbcr_to_8888(*y++, *cb++, *cr++);
  135.         } while(--w);
  136.     }
  137.  
  138.     void VDYCbCrToUYVYSpan(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) {
  139.         uint32 *dst = (uint32 *)dst0;
  140.  
  141.         if (--w) {
  142.             do {
  143.                 *dst++ = (uint32)*cb++ + ((uint32)y[0] << 8) + ((uint32)*cr++ << 16) + ((uint32)y[1] << 24);
  144.                 y += 2;
  145.             } while((sint32)(w-=2)>0);
  146.         }
  147.  
  148.         if (!(w & 1))
  149.             *dst++ = (uint32)*cb + ((uint32)y[0] << 8) + ((uint32)*cr << 16) + ((uint32)y[0] << 24);
  150.     }
  151.  
  152.     void VDYCbCrToYUYVSpan(void *dst0, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 w) {
  153.         uint32 *dst = (uint32 *)dst0;
  154.  
  155.         if (--w) {
  156.             do {
  157.                 *dst++ = (uint32)y[0] + ((uint32)*cb++ << 8) + ((uint32)y[1] << 16) + ((uint32)*cr++ << 24);
  158.                 y += 2;
  159.             } while((sint32)(w-=2)>0);
  160.         }
  161.  
  162.         if (!(w & 1))
  163.             *dst++ = (uint32)y[0] + ((uint32)*cb << 8) + ((uint32)y[0] << 16) + ((uint32)*cr << 24);
  164.     }
  165.  
  166.     void VDYCbCrToRGB1555Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) {
  167.         const ptrdiff_t ystep    = formatinfo.ystep;
  168.         const ptrdiff_t cstep    = formatinfo.cstep;
  169.         const ptrdiff_t ypos0    = formatinfo.ypos[0];
  170.         const ptrdiff_t ypos1    = formatinfo.ypos[1];
  171.         const ptrdiff_t ypos2    = formatinfo.ypos[2];
  172.         const ptrdiff_t ypos3    = formatinfo.ypos[3];
  173.         const ptrdiff_t crpos0    = formatinfo.crpos[0];
  174.         const ptrdiff_t crpos1    = formatinfo.crpos[1];
  175.         const ptrdiff_t crpos2    = formatinfo.crpos[2];
  176.         const ptrdiff_t crpos3    = formatinfo.crpos[3];
  177.         const ptrdiff_t cbpos0    = formatinfo.cbpos[0];
  178.         const ptrdiff_t cbpos1    = formatinfo.cbpos[1];
  179.         const ptrdiff_t cbpos2    = formatinfo.cbpos[2];
  180.         const ptrdiff_t cbpos3    = formatinfo.cbpos[3];
  181.  
  182.         yrow    = (char *)yrow - ystep * ((w-1) >> 2);
  183.         crrow    = (char *)crrow - cstep * ((w-1) >> 2);
  184.         cbrow    = (char *)cbrow - cstep * ((w-1) >> 2);
  185.         dst        = (char *)dst + 2*((w-1) & ~3);
  186.  
  187.         int y = 0;
  188.         do {
  189.             const uint8 *ysrc    = (const uint8 *)yrow;
  190.             const uint8 *crsrc    = (const uint8 *)crrow;
  191.             const uint8 *cbsrc    = (const uint8 *)cbrow;
  192.             uint16 *out = (uint16 *)dst;
  193.             int w2 = -w;
  194.  
  195.             switch(w2 & 3) {
  196.                 do {
  197.             case 0:    out[3] = ycbcr_to_1555(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]);
  198.             case 1:    out[2] = ycbcr_to_1555(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]);
  199.             case 2:    out[1] = ycbcr_to_1555(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]);
  200.             case 3:    out[0] = ycbcr_to_1555(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]);
  201.                     out -= 4;
  202.                     ysrc += ystep;
  203.                     crsrc += cstep;
  204.                     cbsrc += cstep;
  205.                 } while((w2 += 4) < 0);
  206.             }
  207.  
  208.             dst        = (char *)dst + dststride;
  209.             yrow    = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]);
  210.             cbrow    = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]);
  211.             crrow    = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]);
  212.         } while(++y < h);
  213.     }
  214.  
  215.     void VDYCbCrToRGB565Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) {
  216.         const ptrdiff_t ystep    = formatinfo.ystep;
  217.         const ptrdiff_t cstep    = formatinfo.cstep;
  218.         const ptrdiff_t ypos0    = formatinfo.ypos[0];
  219.         const ptrdiff_t ypos1    = formatinfo.ypos[1];
  220.         const ptrdiff_t ypos2    = formatinfo.ypos[2];
  221.         const ptrdiff_t ypos3    = formatinfo.ypos[3];
  222.         const ptrdiff_t crpos0    = formatinfo.crpos[0];
  223.         const ptrdiff_t crpos1    = formatinfo.crpos[1];
  224.         const ptrdiff_t crpos2    = formatinfo.crpos[2];
  225.         const ptrdiff_t crpos3    = formatinfo.crpos[3];
  226.         const ptrdiff_t cbpos0    = formatinfo.cbpos[0];
  227.         const ptrdiff_t cbpos1    = formatinfo.cbpos[1];
  228.         const ptrdiff_t cbpos2    = formatinfo.cbpos[2];
  229.         const ptrdiff_t cbpos3    = formatinfo.cbpos[3];
  230.  
  231.         yrow    = (char *)yrow - ystep * ((w-1) >> 2);
  232.         crrow    = (char *)crrow - cstep * ((w-1) >> 2);
  233.         cbrow    = (char *)cbrow - cstep * ((w-1) >> 2);
  234.         dst        = (char *)dst + 2*((w-1) & ~3);
  235.  
  236.         int y = 0;
  237.         do {
  238.             const uint8 *ysrc = (const uint8 *)yrow;
  239.             const uint8 *crsrc = (const uint8 *)crrow;
  240.             const uint8 *cbsrc = (const uint8 *)cbrow;
  241.             uint16 *out = (uint16 *)dst;
  242.             int w2 = -w;
  243.  
  244.             switch(w2 & 3) {
  245.                 do {
  246.             case 0:    out[3] = ycbcr_to_565(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]);
  247.             case 1:    out[2] = ycbcr_to_565(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]);
  248.             case 2:    out[1] = ycbcr_to_565(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]);
  249.             case 3:    out[0] = ycbcr_to_565(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]);
  250.                     out -= 4;
  251.                     ysrc += ystep;
  252.                     crsrc += cstep;
  253.                     cbsrc += cstep;
  254.                 } while((w2 += 4) < 0);
  255.             }
  256.  
  257.             dst        = (char *)dst + dststride;
  258.             yrow    = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]);
  259.             cbrow    = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]);
  260.             crrow    = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]);
  261.         } while(++y < h);
  262.     }
  263.  
  264.     void VDYCbCrToRGB888Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) {
  265.         const ptrdiff_t ystep    = formatinfo.ystep;
  266.         const ptrdiff_t cstep    = formatinfo.cstep;
  267.         const ptrdiff_t ypos0    = formatinfo.ypos[0];
  268.         const ptrdiff_t ypos1    = formatinfo.ypos[1];
  269.         const ptrdiff_t ypos2    = formatinfo.ypos[2];
  270.         const ptrdiff_t ypos3    = formatinfo.ypos[3];
  271.         const ptrdiff_t crpos0    = formatinfo.crpos[0];
  272.         const ptrdiff_t crpos1    = formatinfo.crpos[1];
  273.         const ptrdiff_t crpos2    = formatinfo.crpos[2];
  274.         const ptrdiff_t crpos3    = formatinfo.crpos[3];
  275.         const ptrdiff_t cbpos0    = formatinfo.cbpos[0];
  276.         const ptrdiff_t cbpos1    = formatinfo.cbpos[1];
  277.         const ptrdiff_t cbpos2    = formatinfo.cbpos[2];
  278.         const ptrdiff_t cbpos3    = formatinfo.cbpos[3];
  279.  
  280.         yrow    = (char *)yrow - ystep * ((w-1) >> 2);
  281.         crrow    = (char *)crrow - cstep * ((w-1) >> 2);
  282.         cbrow    = (char *)cbrow - cstep * ((w-1) >> 2);
  283.         dst        = (char *)dst + 3*((w-1) & ~3);
  284.  
  285.         int y = 0;
  286.         do {
  287.             const uint8 *ysrc    = (const uint8 *)yrow;
  288.             const uint8 *crsrc    = (const uint8 *)crrow;
  289.             const uint8 *cbsrc    = (const uint8 *)cbrow;
  290.             uint8 *out = (uint8 *)dst;
  291.             int w2 = -w;
  292.  
  293.             switch(w2 & 3) {
  294.                 do {
  295.             case 0:    ycbcr_to_888(out+9, ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]);
  296.             case 1:    ycbcr_to_888(out+6, ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]);
  297.             case 2:    ycbcr_to_888(out+3, ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]);
  298.             case 3:    ycbcr_to_888(out, ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]);
  299.                     out -= 12;
  300.                     ysrc += ystep;
  301.                     crsrc += cstep;
  302.                     cbsrc += cstep;
  303.                 } while((w2 += 4) < 0);
  304.             }
  305.  
  306.             dst        = (char *)dst + dststride;
  307.             yrow    = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]);
  308.             cbrow    = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]);
  309.             crrow    = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]);
  310.         } while(++y < h);
  311.     }
  312.  
  313.     void VDYCbCrToRGB8888Generic(void *dst, ptrdiff_t dststride, const void *yrow, ptrdiff_t ystride, const void *cbrow, ptrdiff_t cbstride, const void *crrow, ptrdiff_t crstride, int w, int h, const YCbCrFormatInfo& formatinfo) {
  314.         const ptrdiff_t ystep    = formatinfo.ystep;
  315.         const ptrdiff_t cstep    = formatinfo.cstep;
  316.         const ptrdiff_t ypos0    = formatinfo.ypos[0];
  317.         const ptrdiff_t ypos1    = formatinfo.ypos[1];
  318.         const ptrdiff_t ypos2    = formatinfo.ypos[2];
  319.         const ptrdiff_t ypos3    = formatinfo.ypos[3];
  320.         const ptrdiff_t crpos0    = formatinfo.crpos[0];
  321.         const ptrdiff_t crpos1    = formatinfo.crpos[1];
  322.         const ptrdiff_t crpos2    = formatinfo.crpos[2];
  323.         const ptrdiff_t crpos3    = formatinfo.crpos[3];
  324.         const ptrdiff_t cbpos0    = formatinfo.cbpos[0];
  325.         const ptrdiff_t cbpos1    = formatinfo.cbpos[1];
  326.         const ptrdiff_t cbpos2    = formatinfo.cbpos[2];
  327.         const ptrdiff_t cbpos3    = formatinfo.cbpos[3];
  328.  
  329.         yrow    = (char *)yrow - ystep * ((w-1) >> 2);
  330.         crrow    = (char *)crrow - cstep * ((w-1) >> 2);
  331.         cbrow    = (char *)cbrow - cstep * ((w-1) >> 2);
  332.         dst        = (char *)dst + 4*((w-1) & ~3);
  333.  
  334.         int y = 0;
  335.         do {
  336.             const uint8 *ysrc    = (const uint8 *)yrow;
  337.             const uint8 *crsrc    = (const uint8 *)crrow;
  338.             const uint8 *cbsrc    = (const uint8 *)cbrow;
  339.             uint32 *out = (uint32 *)dst;
  340.             int w2 = -w;
  341.  
  342.             switch(w2 & 3) {
  343.                 do {
  344.             case 0:    out[3] = ycbcr_to_8888(ysrc[ypos3], cbsrc[cbpos3], crsrc[crpos3]);
  345.             case 1:    out[2] = ycbcr_to_8888(ysrc[ypos2], cbsrc[cbpos2], crsrc[crpos2]);
  346.             case 2:    out[1] = ycbcr_to_8888(ysrc[ypos1], cbsrc[cbpos1], crsrc[crpos1]);
  347.             case 3:    out[0] = ycbcr_to_8888(ysrc[ypos0], cbsrc[cbpos0], crsrc[crpos0]);
  348.                     out -= 4;
  349.                     ysrc += ystep;
  350.                     crsrc += cstep;
  351.                     cbsrc += cstep;
  352.                 } while((w2 += 4) < 0);
  353.             }
  354.  
  355.             dst        = (char *)dst + dststride;
  356.             yrow    = (const char *)yrow + (ystride & formatinfo.yinc[y & 3]);
  357.             cbrow    = (const char *)cbrow + (cbstride & formatinfo.cinc[y & 3]);
  358.             crrow    = (const char *)crrow + (crstride & formatinfo.cinc[y & 3]);
  359.         } while(++y < h);
  360.     }
  361. }
  362.  
  363. #define DECLARE_YUV(x, y) void VDPixmapBlt_##x##_to_##y##_reference(void *dst0, ptrdiff_t dstpitch, const void *src0, ptrdiff_t srcpitch, vdpixsize w, vdpixsize h)
  364.  
  365. DECLARE_YUV(UYVY, XRGB1555) {
  366.     do {
  367.         const uint8 *src = (const uint8 *)src0;
  368.         uint16 *dst = (uint16 *)dst0;
  369.  
  370.         // convert first pixel
  371.         int cb, cr;
  372.         int rc0, gc0, bc0, rc1, gc1, bc1;
  373.         const uint16 *y;
  374.  
  375.         cb = src[0];
  376.         cr = src[2];
  377.         rc1 = colorconv.r_cr_tab[cr];
  378.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  379.         bc1 = colorconv.b_cb_tab[cb];
  380.  
  381.         y = &colorconv.cliptab15[277 + colorconv.y_tab[src[1]]];
  382.         *dst++ = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f);
  383.  
  384.         // convert pairs of pixels
  385.         int w2 = w;
  386.  
  387.         if ((w2 -= 2) > 0) {
  388.             do {
  389.                 rc0 = rc1;
  390.                 gc0 = gc1;
  391.                 bc0 = bc1;
  392.  
  393.                 cb = src[4];
  394.                 cr = src[6];
  395.                 rc1 = colorconv.r_cr_tab[cr];
  396.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  397.                 bc1 = colorconv.b_cb_tab[cb];
  398.  
  399.                 y = &colorconv.cliptab15[277 + colorconv.y_tab[src[3]]];
  400.                 dst[0] = (y[(rc0+rc1+1)>>1] & 0x7c00) + (y[(gc0+gc1+1)>>1] & 0x3e0) + (y[(bc0+bc1+1)>>1] & 0x001f);
  401.  
  402.                 y = &colorconv.cliptab15[277 + colorconv.y_tab[src[5]]];
  403.                 dst[1] = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f);
  404.  
  405.                 dst += 2;
  406.                 src += 4;
  407.             } while((w2 -= 2) > 0);
  408.         }
  409.  
  410.         // handle oddballs
  411.         if (!(w2 & 1)) {
  412.             y = &colorconv.cliptab15[277 + colorconv.y_tab[src[3]]];
  413.             *dst = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f);
  414.         }
  415.  
  416.         vdptrstep(src0, srcpitch);
  417.         vdptrstep(dst0, dstpitch);
  418.     } while(--h);
  419. }
  420.  
  421. DECLARE_YUV(UYVY, RGB565) {
  422.     do {
  423.         const uint8 *src = (const uint8 *)src0;
  424.         uint16 *dst = (uint16 *)dst0;
  425.  
  426.         // convert first pixel
  427.         int cb, cr;
  428.         int rc0, gc0, bc0, rc1, gc1, bc1;
  429.         const uint16 *y;
  430.  
  431.         cb = src[0];
  432.         cr = src[2];
  433.         rc1 = colorconv.r_cr_tab[cr];
  434.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  435.         bc1 = colorconv.b_cb_tab[cb];
  436.  
  437.         y = &colorconv.cliptab16[277 + colorconv.y_tab[src[1]]];
  438.         *dst++ = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f);
  439.  
  440.         // convert pairs of pixels
  441.         int w2 = w;
  442.  
  443.         if ((w2 -= 2) > 0) {
  444.             do {
  445.                 rc0 = rc1;
  446.                 gc0 = gc1;
  447.                 bc0 = bc1;
  448.  
  449.                 cb = src[4];
  450.                 cr = src[6];
  451.                 rc1 = colorconv.r_cr_tab[cr];
  452.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  453.                 bc1 = colorconv.b_cb_tab[cb];
  454.  
  455.                 y = &colorconv.cliptab16[277 + colorconv.y_tab[src[3]]];
  456.                 dst[0] = (y[(rc0+rc1+1)>>1] & 0xf800) + (y[(gc0+gc1+1)>>1] & 0x7e0) + (y[(bc0+bc1+1)>>1] & 0x001f);
  457.  
  458.                 y = &colorconv.cliptab16[277 + colorconv.y_tab[src[5]]];
  459.                 dst[1] = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f);
  460.  
  461.                 dst += 2;
  462.                 src += 4;
  463.             } while((w2 -= 2) > 0);
  464.         }
  465.  
  466.         // handle oddballs
  467.         if (!(w2 & 1)) {
  468.             y = &colorconv.cliptab16[277 + colorconv.y_tab[src[3]]];
  469.             *dst = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f);
  470.         }
  471.  
  472.         vdptrstep(src0, srcpitch);
  473.         vdptrstep(dst0, dstpitch);
  474.     } while(--h);
  475. }
  476.  
  477. DECLARE_YUV(UYVY, RGB888) {
  478.     do {
  479.         const uint8 *src = (const uint8 *)src0;
  480.         uint8 *dst = (uint8 *)dst0;
  481.  
  482.         // convert first pixel
  483.         int cb, cr;
  484.         int rc0, gc0, bc0, rc1, gc1, bc1;
  485.         const uint8 *y;
  486.  
  487.         cb = src[0];
  488.         cr = src[2];
  489.         rc1 = colorconv.r_cr_tab[cr];
  490.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  491.         bc1 = colorconv.b_cb_tab[cb];
  492.  
  493.         y = &colorconv.cliptab[277 + colorconv.y_tab[src[1]]];
  494.         dst[0] = y[bc1];
  495.         dst[1] = y[gc1];
  496.         dst[2] = y[rc1];
  497.         dst += 3;
  498.  
  499.         // convert pairs of pixels
  500.         int w2 = w;
  501.  
  502.         if ((w2 -= 2) > 0) {
  503.             do {
  504.                 rc0 = rc1;
  505.                 gc0 = gc1;
  506.                 bc0 = bc1;
  507.  
  508.                 cb = src[4];
  509.                 cr = src[6];
  510.                 rc1 = colorconv.r_cr_tab[cr];
  511.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  512.                 bc1 = colorconv.b_cb_tab[cb];
  513.  
  514.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]];
  515.                 dst[0] = y[(bc0+bc1+1)>>1];
  516.                 dst[1] = y[(gc0+gc1+1)>>1];
  517.                 dst[2] = y[(rc0+rc1+1)>>1];
  518.  
  519.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[5]]];
  520.                 dst[3] = y[bc1];
  521.                 dst[4] = y[gc1];
  522.                 dst[5] = y[rc1];
  523.  
  524.                 dst += 6;
  525.                 src += 4;
  526.             } while((w2 -= 2) > 0);
  527.         }
  528.  
  529.         // handle oddballs
  530.         if (!(w2 & 1)) {
  531.             y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]];
  532.             dst[0] = y[bc1];
  533.             dst[1] = y[gc1];
  534.             dst[2] = y[rc1];
  535.         }
  536.  
  537.         vdptrstep(src0, srcpitch);
  538.         vdptrstep(dst0, dstpitch);
  539.     } while(--h);
  540. }
  541.  
  542. DECLARE_YUV(UYVY, XRGB8888) {
  543.     do {
  544.         const uint8 *src = (const uint8 *)src0;
  545.         uint8 *dst = (uint8 *)dst0;
  546.  
  547.         // convert first pixel
  548.         int cb, cr;
  549.         int rc0, gc0, bc0, rc1, gc1, bc1;
  550.         const uint8 *y;
  551.  
  552.         cb = src[0];
  553.         cr = src[2];
  554.         rc1 = colorconv.r_cr_tab[cr];
  555.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  556.         bc1 = colorconv.b_cb_tab[cb];
  557.  
  558.         y = &colorconv.cliptab[277 + colorconv.y_tab[src[1]]];
  559.         dst[0] = y[bc1];
  560.         dst[1] = y[gc1];
  561.         dst[2] = y[rc1];
  562.         dst += 4;
  563.  
  564.         // convert pairs of pixels
  565.         int w2 = w;
  566.  
  567.         if ((w2 -= 2) > 0) {
  568.             do {
  569.                 rc0 = rc1;
  570.                 gc0 = gc1;
  571.                 bc0 = bc1;
  572.  
  573.                 cb = src[4];
  574.                 cr = src[6];
  575.                 rc1 = colorconv.r_cr_tab[cr];
  576.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  577.                 bc1 = colorconv.b_cb_tab[cb];
  578.  
  579.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]];
  580.                 dst[0] = y[(bc0+bc1+1)>>1];
  581.                 dst[1] = y[(gc0+gc1+1)>>1];
  582.                 dst[2] = y[(rc0+rc1+1)>>1];
  583.  
  584.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[5]]];
  585.                 dst[4] = y[bc1];
  586.                 dst[5] = y[gc1];
  587.                 dst[6] = y[rc1];
  588.  
  589.                 dst += 8;
  590.                 src += 4;
  591.             } while((w2 -= 2) > 0);
  592.         }
  593.  
  594.         // handle oddballs
  595.         if (!(w2 & 1)) {
  596.             y = &colorconv.cliptab[277 + colorconv.y_tab[src[3]]];
  597.             dst[0] = y[bc1];
  598.             dst[1] = y[gc1];
  599.             dst[2] = y[rc1];
  600.         }
  601.  
  602.         vdptrstep(src0, srcpitch);
  603.         vdptrstep(dst0, dstpitch);
  604.     } while(--h);
  605. }
  606.  
  607. DECLARE_YUV(YUYV, XRGB1555) {
  608.     do {
  609.         const uint8 *src = (const uint8 *)src0;
  610.         uint16 *dst = (uint16 *)dst0;
  611.  
  612.         // convert first pixel
  613.         int cb, cr;
  614.         int rc0, gc0, bc0, rc1, gc1, bc1;
  615.         const uint16 *y;
  616.  
  617.         cb = src[1];
  618.         cr = src[3];
  619.         rc1 = colorconv.r_cr_tab[cr];
  620.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  621.         bc1 = colorconv.b_cb_tab[cb];
  622.  
  623.         y = &colorconv.cliptab15[277 + colorconv.y_tab[src[0]]];
  624.         *dst++ = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f);
  625.  
  626.         // convert pairs of pixels
  627.         int w2 = w;
  628.  
  629.         if ((w2 -= 2) > 0) {
  630.             do {
  631.                 rc0 = rc1;
  632.                 gc0 = gc1;
  633.                 bc0 = bc1;
  634.  
  635.                 cb = src[5];
  636.                 cr = src[7];
  637.                 rc1 = colorconv.r_cr_tab[cr];
  638.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  639.                 bc1 = colorconv.b_cb_tab[cb];
  640.  
  641.                 y = &colorconv.cliptab15[277 + colorconv.y_tab[src[2]]];
  642.                 dst[0] = (y[(rc0+rc1+1)>>1] & 0x7c00) + (y[(gc0+gc1+1)>>1] & 0x3e0) + (y[(bc0+bc1+1)>>1] & 0x001f);
  643.  
  644.                 y = &colorconv.cliptab15[277 + colorconv.y_tab[src[4]]];
  645.                 dst[1] = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f);
  646.  
  647.                 dst += 2;
  648.                 src += 4;
  649.             } while((w2 -= 2) > 0);
  650.         }
  651.  
  652.         // handle oddballs
  653.         if (!(w2 & 1)) {
  654.             y = &colorconv.cliptab15[277 + colorconv.y_tab[src[2]]];
  655.             *dst = (y[rc1] & 0x7c00) + (y[gc1] & 0x3e0) + (y[bc1] & 0x001f);
  656.         }
  657.  
  658.         vdptrstep(src0, srcpitch);
  659.         vdptrstep(dst0, dstpitch);
  660.     } while(--h);
  661. }
  662.  
  663. DECLARE_YUV(YUYV, RGB565) {
  664.     do {
  665.         const uint8 *src = (const uint8 *)src0;
  666.         uint16 *dst = (uint16 *)dst0;
  667.  
  668.         // convert first pixel
  669.         int cb, cr;
  670.         int rc0, gc0, bc0, rc1, gc1, bc1;
  671.         const uint16 *y;
  672.  
  673.         cb = src[1];
  674.         cr = src[3];
  675.         rc1 = colorconv.r_cr_tab[cr];
  676.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  677.         bc1 = colorconv.b_cb_tab[cb];
  678.  
  679.         y = &colorconv.cliptab16[277 + colorconv.y_tab[src[0]]];
  680.         *dst++ = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f);
  681.  
  682.         // convert pairs of pixels
  683.         int w2 = w;
  684.  
  685.         if ((w2 -= 2) > 0) {
  686.             do {
  687.                 rc0 = rc1;
  688.                 gc0 = gc1;
  689.                 bc0 = bc1;
  690.  
  691.                 cb = src[5];
  692.                 cr = src[7];
  693.                 rc1 = colorconv.r_cr_tab[cr];
  694.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  695.                 bc1 = colorconv.b_cb_tab[cb];
  696.  
  697.                 y = &colorconv.cliptab16[277 + colorconv.y_tab[src[2]]];
  698.                 dst[0] = (y[(rc0+rc1+1)>>1] & 0xf800) + (y[(gc0+gc1+1)>>1] & 0x7e0) + (y[(bc0+bc1+1)>>1] & 0x001f);
  699.  
  700.                 y = &colorconv.cliptab16[277 + colorconv.y_tab[src[4]]];
  701.                 dst[1] = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f);
  702.  
  703.                 dst += 2;
  704.                 src += 4;
  705.             } while((w2 -= 2) > 0);
  706.         }
  707.  
  708.         // handle oddballs
  709.         if (!(w2 & 1)) {
  710.             y = &colorconv.cliptab16[277 + colorconv.y_tab[src[2]]];
  711.             *dst = (y[rc1] & 0xf800) + (y[gc1] & 0x7e0) + (y[bc1] & 0x001f);
  712.         }
  713.  
  714.         vdptrstep(src0, srcpitch);
  715.         vdptrstep(dst0, dstpitch);
  716.     } while(--h);
  717. }
  718.  
  719. DECLARE_YUV(YUYV, RGB888) {
  720.     do {
  721.         const uint8 *src = (const uint8 *)src0;
  722.         uint8 *dst = (uint8 *)dst0;
  723.  
  724.         // convert first pixel
  725.         int cb, cr;
  726.         int rc0, gc0, bc0, rc1, gc1, bc1;
  727.         const uint8 *y;
  728.  
  729.         cb = src[1];
  730.         cr = src[3];
  731.         rc1 = colorconv.r_cr_tab[cr];
  732.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  733.         bc1 = colorconv.b_cb_tab[cb];
  734.  
  735.         y = &colorconv.cliptab[277 + colorconv.y_tab[src[0]]];
  736.         dst[0] = y[bc1];
  737.         dst[1] = y[gc1];
  738.         dst[2] = y[rc1];
  739.         dst += 3;
  740.  
  741.         // convert pairs of pixels
  742.         int w2 = w;
  743.  
  744.         if ((w2 -= 2) > 0) {
  745.             do {
  746.                 rc0 = rc1;
  747.                 gc0 = gc1;
  748.                 bc0 = bc1;
  749.  
  750.                 cb = src[5];
  751.                 cr = src[7];
  752.                 rc1 = colorconv.r_cr_tab[cr];
  753.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  754.                 bc1 = colorconv.b_cb_tab[cb];
  755.  
  756.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]];
  757.                 dst[0] = y[(bc0+bc1+1)>>1];
  758.                 dst[1] = y[(gc0+gc1+1)>>1];
  759.                 dst[2] = y[(rc0+rc1+1)>>1];
  760.  
  761.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[4]]];
  762.                 dst[3] = y[bc1];
  763.                 dst[4] = y[gc1];
  764.                 dst[5] = y[rc1];
  765.  
  766.                 dst += 6;
  767.                 src += 4;
  768.             } while((w2 -= 2) > 0);
  769.         }
  770.  
  771.         // handle oddballs
  772.         if (!(w2 & 1)) {
  773.             y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]];
  774.             dst[0] = y[bc1];
  775.             dst[1] = y[gc1];
  776.             dst[2] = y[rc1];
  777.         }
  778.  
  779.         vdptrstep(src0, srcpitch);
  780.         vdptrstep(dst0, dstpitch);
  781.     } while(--h);
  782. }
  783.  
  784. DECLARE_YUV(YUYV, XRGB8888) {
  785.     do {
  786.         const uint8 *src = (const uint8 *)src0;
  787.         uint8 *dst = (uint8 *)dst0;
  788.  
  789.         // convert first pixel
  790.         int cb, cr;
  791.         int rc0, gc0, bc0, rc1, gc1, bc1;
  792.         const uint8 *y;
  793.  
  794.         cb = src[1];
  795.         cr = src[3];
  796.         rc1 = colorconv.r_cr_tab[cr];
  797.         gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  798.         bc1 = colorconv.b_cb_tab[cb];
  799.  
  800.         y = &colorconv.cliptab[277 + colorconv.y_tab[src[0]]];
  801.         dst[0] = y[bc1];
  802.         dst[1] = y[gc1];
  803.         dst[2] = y[rc1];
  804.         dst += 4;
  805.  
  806.         // convert pairs of pixels
  807.         int w2 = w;
  808.  
  809.         if ((w2 -= 2) > 0) {
  810.             do {
  811.                 rc0 = rc1;
  812.                 gc0 = gc1;
  813.                 bc0 = bc1;
  814.  
  815.                 cb = src[5];
  816.                 cr = src[7];
  817.                 rc1 = colorconv.r_cr_tab[cr];
  818.                 gc1 = colorconv.g_cr_tab[cr] + colorconv.g_cb_tab[cb];
  819.                 bc1 = colorconv.b_cb_tab[cb];
  820.  
  821.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]];
  822.                 dst[0] = y[(bc0+bc1+1)>>1];
  823.                 dst[1] = y[(gc0+gc1+1)>>1];
  824.                 dst[2] = y[(rc0+rc1+1)>>1];
  825.  
  826.                 y = &colorconv.cliptab[277 + colorconv.y_tab[src[4]]];
  827.                 dst[4] = y[bc1];
  828.                 dst[5] = y[gc1];
  829.                 dst[6] = y[rc1];
  830.  
  831.                 dst += 8;
  832.                 src += 4;
  833.             } while((w2 -= 2) > 0);
  834.         }
  835.  
  836.         // handle oddballs
  837.         if (!(w2 & 1)) {
  838.             y = &colorconv.cliptab[277 + colorconv.y_tab[src[2]]];
  839.             dst[0] = y[bc1];
  840.             dst[1] = y[gc1];
  841.             dst[2] = y[rc1];
  842.         }
  843.  
  844.         vdptrstep(src0, srcpitch);
  845.         vdptrstep(dst0, dstpitch);
  846.     } while(--h);
  847. }
  848.  
  849. DECLARE_YUV(Y8, XRGB1555) {
  850.     uint16 *dst = (uint16 *)dst0;
  851.     const uint8 *src = (const uint8 *)src0;
  852.  
  853.     dstpitch -= 2*w;
  854.     srcpitch -= w;
  855.  
  856.     do {
  857.         vdpixsize w2 = w;
  858.  
  859.         do {
  860.             *dst++ = colorconv.cliptab15[colorconv.y_tab[*src++] + 277];
  861.         } while(--w2);
  862.  
  863.         vdptrstep(src, srcpitch);
  864.         vdptrstep(dst, dstpitch);
  865.     } while(--h);
  866. }
  867.  
  868. DECLARE_YUV(Y8, RGB565) {
  869.     uint16 *dst = (uint16 *)dst0;
  870.     const uint8 *src = (const uint8 *)src0;
  871.  
  872.     dstpitch -= 2*w;
  873.     srcpitch -= w;
  874.  
  875.     do {
  876.         vdpixsize w2 = w;
  877.  
  878.         do {
  879.             *dst++ = colorconv.cliptab16[colorconv.y_tab[*src++] + 277];
  880.         } while(--w2);
  881.  
  882.         vdptrstep(src, srcpitch);
  883.         vdptrstep(dst, dstpitch);
  884.     } while(--h);
  885. }
  886.  
  887. DECLARE_YUV(Y8, RGB888) {
  888.     uint8 *dst = (uint8 *)dst0;
  889.     const uint8 *src = (const uint8 *)src0;
  890.  
  891.     dstpitch -= 3*w;
  892.     srcpitch -= w;
  893.  
  894.     do {
  895.         vdpixsize w2 = w;
  896.  
  897.         do {
  898.             dst[0] = dst[1] = dst[2] = colorconv.cliptab[colorconv.y_tab[*src++] + 277];
  899.             dst += 3;
  900.         } while(--w2);
  901.  
  902.         vdptrstep(src, srcpitch);
  903.         vdptrstep(dst, dstpitch);
  904.     } while(--h);
  905. }
  906.  
  907. DECLARE_YUV(Y8, XRGB8888) {
  908.     uint32 *dst = (uint32 *)dst0;
  909.     const uint8 *src = (const uint8 *)src0;
  910.  
  911.     dstpitch -= 4*w;
  912.     srcpitch -= w;
  913.  
  914.     do {
  915.         vdpixsize w2 = w;
  916.  
  917.         do {
  918.             *dst++ = 0x010101 * colorconv.cliptab[colorconv.y_tab[*src++] + 277];
  919.         } while(--w2);
  920.  
  921.         vdptrstep(src, srcpitch);
  922.         vdptrstep(dst, dstpitch);
  923.     } while(--h);
  924. }
  925.  
  926. #define DECLARE_YUV_PLANAR(x, y) void VDPixmapBlt_##x##_to_##y##_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h)
  927.  
  928.  
  929. namespace {
  930.     typedef void (*tpYUVPlanarFinalDecoder)(void *, const uint8 *, const uint8 *, const uint8 *, uint32);
  931.     typedef void (*tpYUVPlanarHorizDecoder)(uint8 *dst, const uint8 *src, sint32 w);
  932.     typedef void (*tpYUVPlanarVertDecoder)(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase);
  933. }
  934.  
  935. #ifdef _M_IX86
  936.     extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count);
  937.     extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count);
  938.     extern "C" void __cdecl vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX(void *dst, const uint8 *y, const uint8 *cb, const uint8 *cr, uint32 count);
  939. #endif
  940.  
  941.  
  942. void VDPixmapBlt_YUVPlanar_decode_reference(const VDPixmap& dst, const VDPixmap& src, vdpixsize w, vdpixsize h) {
  943.     const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(src.format);
  944.     int hbits = srcinfo.auxwbits;
  945.     int vbits = srcinfo.auxhbits;
  946.  
  947.     if (src.format == nsVDPixmap::kPixFormat_YUV422_UYVY || src.format == nsVDPixmap::kPixFormat_YUV422_YUYV)
  948.         hbits = 1;
  949.  
  950.     bool h_coaligned = true;
  951.     bool v_coaligned = false;
  952.  
  953.     if (src.format == nsVDPixmap::kPixFormat_YUV422_Planar_Centered ||
  954.         src.format == nsVDPixmap::kPixFormat_YUV420_Planar_Centered) {
  955.         h_coaligned = false;
  956.     }
  957.  
  958.     tpYUVPlanarVertDecoder vfunc = NULL;
  959.     tpYUVPlanarHorizDecoder hfunc = NULL;
  960.     uint32 horiz_buffer_size = 0;
  961.     uint32 vert_buffer_size = 0;
  962.     uint32 horiz_count = 0;
  963.     sint32 yaccum = 8;
  964.     sint32 yinc = 8;
  965.     uint32 yleft = h;
  966.  
  967.     switch(vbits*2+v_coaligned) {
  968.     case 0:        // 4:4:4, 4:2:2
  969.     case 1:
  970.         break;
  971.     case 2:        // 4:2:0 (centered) 
  972.         vfunc = vert_expand2x_centered;
  973.         vert_buffer_size = w>>1;
  974.         yaccum = 6;
  975.         yinc = 4;
  976.         yleft >>= 1;
  977.         break;
  978.     case 4:        // 4:1:0 (centered)
  979.         vfunc = vert_expand4x_centered;
  980.         vert_buffer_size = w>>2;
  981.         yaccum = 5;
  982.         yinc = 2;
  983.         yleft >>= 2;
  984.         break;
  985.     default:
  986.         VDNEVERHERE;
  987.         return;
  988.     }
  989.  
  990.     --yleft;
  991.  
  992.     tpYUVPlanarFinalDecoder dfunc = NULL;
  993.  
  994. #ifdef _M_IX86
  995.     uint32 cpuflags = CPUGetEnabledExtensions();
  996.  
  997.     if (cpuflags & CPUF_SUPPORTS_MMX) {
  998.         if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) {
  999.             if (vfunc == vert_expand2x_centered)
  1000.                 vfunc = vert_expand2x_centered_ISSE;
  1001.         }
  1002.  
  1003.         switch(dst.format) {
  1004.         case nsVDPixmap::kPixFormat_XRGB1555:    dfunc = vdasm_pixblt_YUV444Planar_to_XRGB1555_scan_MMX;    break;
  1005.         case nsVDPixmap::kPixFormat_RGB565:        dfunc = vdasm_pixblt_YUV444Planar_to_RGB565_scan_MMX;    break;
  1006.         case nsVDPixmap::kPixFormat_XRGB8888:    dfunc = vdasm_pixblt_YUV444Planar_to_XRGB8888_scan_MMX;    break;
  1007.         }
  1008.     }
  1009. #endif
  1010.  
  1011.     bool halfchroma = false;
  1012.  
  1013.     if (!dfunc) {
  1014.         switch(dst.format) {
  1015.         case nsVDPixmap::kPixFormat_XRGB1555:        dfunc = VDYCbCrToXRGB1555Span;    break;
  1016.         case nsVDPixmap::kPixFormat_RGB565:            dfunc = VDYCbCrToRGB565Span;    break;
  1017.         case nsVDPixmap::kPixFormat_RGB888:            dfunc = VDYCbCrToRGB888Span;    break;
  1018.         case nsVDPixmap::kPixFormat_XRGB8888:        dfunc = VDYCbCrToXRGB8888Span;    break;
  1019.         case nsVDPixmap::kPixFormat_YUV422_UYVY:    dfunc = VDYCbCrToUYVYSpan;        halfchroma = true;    break;
  1020.         case nsVDPixmap::kPixFormat_YUV422_YUYV:    dfunc = VDYCbCrToYUYVSpan;        halfchroma = true;    break;
  1021.         default:
  1022.             VDNEVERHERE;
  1023.             return;
  1024.         }
  1025.     }
  1026.  
  1027.     switch(hbits*2+h_coaligned) {
  1028.     case 0:        // 4:4:4
  1029.     case 1:
  1030.         if (halfchroma) {
  1031.             hfunc = horiz_compress2x_coaligned;
  1032.             horiz_buffer_size = (w + 1) >> 1;
  1033.             horiz_count = w;
  1034.         }
  1035.         break;
  1036.     case 2:        // 4:2:0 MPEG-1 (centered)
  1037.         if (halfchroma) {
  1038.             hfunc = horiz_realign_to_coaligned;
  1039.             horiz_buffer_size = (w + 1) >> 1;
  1040.             horiz_count = (w + 1) >> 1;
  1041.         } else {
  1042.             hfunc = horiz_expand2x_centered;
  1043.             horiz_buffer_size = w;
  1044.             horiz_count = w;
  1045.         }
  1046.         break;
  1047.     case 3:        // 4:2:0/4:2:2 MPEG-2 (coaligned)
  1048.         if (!halfchroma) {
  1049.             hfunc = horiz_expand2x_coaligned;
  1050.             horiz_buffer_size = w;
  1051.             horiz_count = w;
  1052.         }
  1053.         break;
  1054.     case 5:        // 4:1:1 (coaligned)
  1055.         if (halfchroma) {
  1056.             hfunc = horiz_expand2x_coaligned;
  1057.             horiz_buffer_size = (w + 1) >> 1;
  1058.             horiz_count = (w + 1) >> 1;
  1059.         } else {
  1060.             hfunc = horiz_expand4x_coaligned;
  1061.             horiz_buffer_size = w;
  1062.             horiz_count = w;
  1063.         }
  1064.         break;
  1065.  
  1066.     default:
  1067.         VDNEVERHERE;
  1068.         return;
  1069.     }
  1070.  
  1071. #ifdef _M_IX86
  1072.     if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) {
  1073.         if (hfunc == horiz_expand2x_coaligned)
  1074.             hfunc = horiz_expand2x_coaligned_ISSE;
  1075.     }
  1076. #endif
  1077.  
  1078.     uint32 chroma_srcwidth = -(-w >> srcinfo.auxwbits);
  1079.     horiz_buffer_size = (horiz_buffer_size + 15) & ~15;
  1080.     vert_buffer_size = (vert_buffer_size + 15) & ~15;
  1081.  
  1082.     // allocate buffers
  1083.  
  1084.     vdblock<uint8> tempbuf((horiz_buffer_size + vert_buffer_size)*2 + 1);
  1085.  
  1086.     uint8 *const crbufh = tempbuf.data();
  1087.     uint8 *const crbufv = crbufh + horiz_buffer_size;
  1088.     uint8 *const cbbufh = crbufv + vert_buffer_size;
  1089.     uint8 *const cbbufv = cbbufh + horiz_buffer_size;
  1090.  
  1091.     const uint8 *cb0 = (const uint8*)src.data2;
  1092.     const uint8 *cr0 = (const uint8*)src.data3;
  1093.     const uint8 *cb1  = cb0;
  1094.     const uint8 *cr1  = cr0;
  1095.     const uint8 *y = (const uint8 *)src.data;
  1096.     const ptrdiff_t ypitch = src.pitch;
  1097.     const ptrdiff_t cbpitch = src.pitch2;
  1098.     const ptrdiff_t crpitch = src.pitch3;
  1099.  
  1100.     void *out = dst.data;
  1101.     ptrdiff_t outpitch = dst.pitch;
  1102.  
  1103.     for(;;) {
  1104.         if (yaccum >= 8) {
  1105.             yaccum &= 7;
  1106.  
  1107.             cb0 = cb1;
  1108.             cr0 = cr1;
  1109.  
  1110.             if (yleft > 0) {
  1111.                 --yleft;
  1112.                 vdptrstep(cb1, cbpitch);
  1113.                 vdptrstep(cr1, crpitch);
  1114.             }
  1115.         }
  1116.  
  1117.         const uint8 *cr = cr0;
  1118.         const uint8 *cb = cb0;
  1119.  
  1120.         // vertical interpolation: cr
  1121.         if(yaccum & 7) {
  1122.             const uint8 *const srcs[2]={cr0, cr1};
  1123.             vfunc(crbufv, srcs, chroma_srcwidth, (yaccum & 7) << 5);
  1124.             cr = crbufv;
  1125.         }
  1126.  
  1127.         // horizontal interpolation: cr
  1128.         if (hfunc) {
  1129.             hfunc(crbufh, cr, horiz_count);
  1130.             cr = crbufh;
  1131.         }
  1132.  
  1133.         // vertical interpolation: cb
  1134.         if(yaccum & 7) {
  1135.             const uint8 *const srcs[2]={cb0, cb1};
  1136.             vfunc(cbbufv, srcs, chroma_srcwidth, (yaccum & 7) << 5);
  1137.             cb = cbbufv;
  1138.         }
  1139.  
  1140.         // horizontal interpolation: cb
  1141.         if (hfunc) {
  1142.             hfunc(cbbufh, cb, horiz_count);
  1143.             cb = cbbufh;
  1144.         }
  1145.  
  1146.         dfunc(out, y, cb, cr, w);
  1147.         vdptrstep(out, outpitch);
  1148.         vdptrstep(y, ypitch);
  1149.  
  1150.         if (!--h)
  1151.             break;
  1152.  
  1153.         yaccum += yinc;
  1154.     }
  1155.  
  1156. #ifdef _M_IX86
  1157.     if (cpuflags & CPUF_SUPPORTS_MMX) {
  1158.         __asm emms
  1159.     }
  1160. #endif
  1161. }
  1162.  
  1163. namespace {
  1164.     typedef void (*tpUVBltHorizDecoder)(uint8 *dst, const uint8 *src, sint32 w);
  1165.     typedef void (*tpUVBltVertDecoder)(uint8 *dst, const uint8 *const *srcs, sint32 w, uint8 phase);
  1166.  
  1167.     void uvplaneblt(uint8 *dst, ptrdiff_t dstpitch, int dstformat, const uint8 *src, ptrdiff_t srcpitch, int srcformat, vdpixsize w, vdpixsize h) {
  1168.         const VDPixmapFormatInfo& srcinfo = VDPixmapGetInfo(srcformat);
  1169.         const VDPixmapFormatInfo& dstinfo = VDPixmapGetInfo(dstformat);
  1170.  
  1171.         int xshift = srcinfo.auxwbits - dstinfo.auxwbits;
  1172.         int yshift = srcinfo.auxhbits - dstinfo.auxhbits;
  1173.  
  1174.         tpUVBltHorizDecoder        hfunc = NULL;
  1175.         tpUVBltVertDecoder        vfunc = NULL;
  1176.  
  1177.         switch(xshift) {
  1178.         case +2:
  1179.             hfunc = horiz_expand4x_coaligned;
  1180.             break;
  1181.         case +1:
  1182.             hfunc = horiz_expand2x_coaligned;
  1183.             break;
  1184.         case  0:
  1185.             break;
  1186.         case -1:
  1187.             hfunc = horiz_compress2x_coaligned;
  1188.             break;
  1189.         case -2:
  1190.             hfunc = horiz_compress4x_coaligned;
  1191.             break;
  1192.         default:
  1193.             VDNEVERHERE;
  1194.             return;
  1195.         }
  1196.  
  1197. #ifdef _M_IX86
  1198.         uint32 cpuflags = CPUGetEnabledExtensions();
  1199.  
  1200.         if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) {
  1201.             if (hfunc == horiz_expand2x_coaligned)
  1202.                 hfunc = horiz_expand2x_coaligned_ISSE;
  1203.         }
  1204. #endif
  1205.  
  1206.         int winsize, winposnext, winstep;
  1207.  
  1208.         switch(yshift) {
  1209.         case +2:
  1210.             vfunc = vert_expand4x_centered;
  1211.             winsize = 2;
  1212.             winposnext = 0xa0;
  1213.             winstep = 0x40;
  1214.             break;
  1215.         case +1:
  1216.             vfunc = vert_expand2x_centered;
  1217.             winsize = 2;
  1218.             winposnext = 0xc0;
  1219.             winstep = 0x80;
  1220.             break;
  1221.         case  0:
  1222.             winsize = 1;
  1223.             winposnext = 0;
  1224.             winstep = 0x100;
  1225.             break;
  1226.         case -1:
  1227.             vfunc = vert_compress2x_centered;
  1228.             winsize = 4;
  1229.             winposnext = 0x200;
  1230.             winstep = 0x200;
  1231.             break;
  1232.         case -2:
  1233.             vfunc = vert_compress4x_centered;
  1234.             winsize = 8;
  1235.             winposnext = 0x500;
  1236.             winstep = 0x400;
  1237.             break;
  1238.         default:
  1239.             VDNEVERHERE;
  1240.             return;
  1241.         }
  1242.  
  1243. #ifdef _M_IX86
  1244.         if (cpuflags & CPUF_SUPPORTS_INTEGER_SSE) {
  1245.             if (vfunc == vert_expand2x_centered)
  1246.                 vfunc = vert_expand2x_centered_ISSE;
  1247.         }
  1248. #endif
  1249.  
  1250.         int dsth = -(-h >> dstinfo.auxhbits);
  1251.         int srch = -(-h >> srcinfo.auxhbits);
  1252.         int dstw = -(-w >> dstinfo.auxwbits);
  1253.         int w2 = -(-w >> std::min<int>(dstinfo.auxwbits, srcinfo.auxwbits));
  1254.  
  1255.         int winpos = (winposnext>>8) - winsize;
  1256.  
  1257.         const uint8 *window[16];
  1258.  
  1259.         vdblock<uint8> tmpbuf;
  1260.         ptrdiff_t tmppitch = (w+15) & ~15;
  1261.  
  1262.         if (vfunc && hfunc)
  1263.             tmpbuf.resize(tmppitch * winsize);
  1264.  
  1265.         do {
  1266.             int desiredpos = winposnext >> 8;
  1267.  
  1268.             while(winpos < desiredpos) {
  1269.                 const uint8 *srcrow = vdptroffset(src, srcpitch * std::max<int>(0, std::min<int>(srch-1, ++winpos)));
  1270.                 int winoffset = (winpos-1) & (winsize-1);
  1271.  
  1272.                 if (hfunc) {
  1273.                     uint8 *dstrow = vfunc ? tmpbuf.data() + tmppitch * winoffset : dst;
  1274.                     hfunc(dstrow, srcrow, w2);
  1275.                     srcrow = dstrow;
  1276.                 }
  1277.  
  1278.                 window[winoffset] = window[winoffset + winsize] = srcrow;
  1279.             }
  1280.  
  1281.             if (vfunc)
  1282.                 vfunc(dst, window + (winpos & (winsize-1)), dstw, winposnext & 255);
  1283.             else if (!hfunc)
  1284.                 memcpy(dst, window[winpos & (winsize-1)], dstw);
  1285.  
  1286.             winposnext += winstep;
  1287.             vdptrstep(dst, dstpitch);
  1288.         } while(--dsth);
  1289.  
  1290. #ifdef _M_IX86
  1291.         if (cpuflags & CPUF_SUPPORTS_MMX) {
  1292.             __asm emms
  1293.         }
  1294. #endif
  1295.     }
  1296. }
  1297.  
  1298. void VDPixmapBlt_YUVPlanar_convert_reference(const VDPixmap& dstpm, const VDPixmap& srcpm, vdpixsize w, vdpixsize h) {
  1299.     VDMemcpyRect(dstpm.data, dstpm.pitch, srcpm.data, srcpm.pitch, dstpm.w, dstpm.h);
  1300.  
  1301.     if (srcpm.format != nsVDPixmap::kPixFormat_Y8) {
  1302.         if (dstpm.format != nsVDPixmap::kPixFormat_Y8) {
  1303.             // YCbCr -> YCbCr
  1304.             uvplaneblt((uint8 *)dstpm.data2, dstpm.pitch2, dstpm.format, (uint8 *)srcpm.data2, srcpm.pitch2, srcpm.format, w, h);
  1305.             uvplaneblt((uint8 *)dstpm.data3, dstpm.pitch3, dstpm.format, (uint8 *)srcpm.data3, srcpm.pitch3, srcpm.format, w, h);
  1306.         }
  1307.     } else {
  1308.         if (dstpm.format != nsVDPixmap::kPixFormat_Y8) {
  1309.             const VDPixmapFormatInfo& info = VDPixmapGetInfo(dstpm.format);
  1310.             VDMemset8Rect(dstpm.data2, dstpm.pitch2, 0x80, -(-w >> info.auxwbits), -(-h >> info.auxhbits));
  1311.             VDMemset8Rect(dstpm.data3, dstpm.pitch3, 0x80, -(-w >> info.auxwbits), -(-h >> info.auxhbits));
  1312.         }
  1313.     }
  1314. }
  1315.  
  1316. extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count);
  1317. extern "C" void vdasm_pixblt_YUV411Planar_to_RGB565_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count);
  1318. extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX(void *dst, const void *y, const void *cb, const void *cr, unsigned count);
  1319. extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count);
  1320. extern "C" void vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count);
  1321. extern "C" void vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_ISSE(void *dst, const void *y, const void *cb, const void *cr, unsigned count);
  1322.  
  1323. DECLARE_YUV_PLANAR(YUV411, XRGB1555) {
  1324.     uint16            *out    = (uint16 *)dst.data;
  1325.     const ptrdiff_t    opitch    = dst.pitch;
  1326.     const uint8        *yrow    = (const uint8 *)src.data;
  1327.     const uint8        *cbrow    = (const uint8 *)src.data2;
  1328.     const uint8        *crrow    = (const uint8 *)src.data3;
  1329.     const ptrdiff_t    ypitch    = src.pitch;
  1330.     const ptrdiff_t    cbpitch    = src.pitch2;
  1331.     const ptrdiff_t    crpitch    = src.pitch3;
  1332.  
  1333.     vdpixsize wpairs = (w-1)>>2;
  1334.     vdpixsize wleft = w - (wpairs<<2);
  1335.  
  1336.     do {
  1337.         uint16 *p = out;
  1338.         const uint8 *y = yrow;
  1339.         const uint8 *cb = cbrow;
  1340.         const uint8 *cr = crrow;
  1341.         vdpixsize wt;
  1342.  
  1343.         if (wpairs > 0) {
  1344. #ifdef _M_AMD64
  1345.             wt = wpairs;
  1346.  
  1347.             do {
  1348.                 const unsigned cb0 = cb[0];
  1349.                 const unsigned cb1 = cb[1];
  1350.                 const unsigned cr0 = cr[0];
  1351.                 const unsigned cr1 = cr[1];
  1352.  
  1353.                 p[0] = ycbcr_to_1555(y[0], cb0, cr0);
  1354.                 p[1] = ycbcr_to_1555(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2);
  1355.                 p[2] = ycbcr_to_1555(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1);
  1356.                 p[3] = ycbcr_to_1555(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2);
  1357.  
  1358.                 y += 4;
  1359.                 p += 4;
  1360.                 ++cb;
  1361.                 ++cr;
  1362.             } while(--wt);
  1363. #else
  1364.             vdasm_pixblt_YUV411Planar_to_XRGB1555_scan_ISSE(p, y, cb, cr, wpairs);
  1365.             y += 4*wpairs;
  1366.             cr += wpairs;
  1367.             cb += wpairs;
  1368.             p += 4*wpairs;
  1369. #endif
  1370.         }
  1371.  
  1372.         if (wleft > 0) {
  1373.             wt = wleft;
  1374.  
  1375.             const uint8 cr0 = *cr;
  1376.             const uint8 cb0 = *cb;
  1377.  
  1378.             do {
  1379.                 *p++ = ycbcr_to_1555(*y++, cb0, cr0);
  1380.             } while(--wt);
  1381.         }
  1382.  
  1383.         vdptrstep(out, opitch);
  1384.         vdptrstep(yrow, ypitch);
  1385.         vdptrstep(cbrow, cbpitch);
  1386.         vdptrstep(crrow, crpitch);
  1387.     } while(--h);
  1388.  
  1389. #ifndef _M_AMD64
  1390.     __asm emms
  1391. #endif
  1392. }
  1393.  
  1394. DECLARE_YUV_PLANAR(YUV411, RGB565) {
  1395.     uint16            *out    = (uint16 *)dst.data;
  1396.     const ptrdiff_t    opitch    = dst.pitch;
  1397.     const uint8        *yrow    = (const uint8 *)src.data;
  1398.     const uint8        *cbrow    = (const uint8 *)src.data2;
  1399.     const uint8        *crrow    = (const uint8 *)src.data3;
  1400.     const ptrdiff_t    ypitch    = src.pitch;
  1401.     const ptrdiff_t    cbpitch    = src.pitch2;
  1402.     const ptrdiff_t    crpitch    = src.pitch3;
  1403.  
  1404.     vdpixsize wpairs = (w-1)>>2;
  1405.     vdpixsize wleft = w - (wpairs<<2);
  1406.  
  1407.     do {
  1408.         uint16 *p = out;
  1409.         const uint8 *y = yrow;
  1410.         const uint8 *cb = cbrow;
  1411.         const uint8 *cr = crrow;
  1412.         vdpixsize wt;
  1413.  
  1414.         if (wpairs > 0) {
  1415. #if _M_AMD64
  1416.             wt = wpairs;
  1417.  
  1418.             do {
  1419.                 const unsigned cb0 = cb[0];
  1420.                 const unsigned cb1 = cb[1];
  1421.                 const unsigned cr0 = cr[0];
  1422.                 const unsigned cr1 = cr[1];
  1423.  
  1424.                 p[0] = ycbcr_to_565(y[0], cb0, cr0);
  1425.                 p[1] = ycbcr_to_565(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2);
  1426.                 p[2] = ycbcr_to_565(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1);
  1427.                 p[3] = ycbcr_to_565(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2);
  1428.  
  1429.                 y += 4;
  1430.                 p += 4;
  1431.                 ++cb;
  1432.                 ++cr;
  1433.             } while(--wt);
  1434. #else
  1435.             vdasm_pixblt_YUV411Planar_to_RGB565_scan_ISSE(p, y, cb, cr, wpairs);
  1436. #endif
  1437.         }
  1438.  
  1439.         if (wleft > 0) {
  1440.             wt = wleft;
  1441.  
  1442.             const uint8 cr0 = *cr;
  1443.             const uint8 cb0 = *cb;
  1444.  
  1445.             do {
  1446.                 *p++ = ycbcr_to_565(*y++, cb0, cr0);
  1447.             } while(--wt);
  1448.         }
  1449.  
  1450.         vdptrstep(out, opitch);
  1451.         vdptrstep(yrow, ypitch);
  1452.         vdptrstep(cbrow, cbpitch);
  1453.         vdptrstep(crrow, crpitch);
  1454.     } while(--h);
  1455.  
  1456. #ifndef _M_AMD64
  1457.     __asm emms
  1458. #endif
  1459. }
  1460.  
  1461. DECLARE_YUV_PLANAR(YUV411, RGB888) {
  1462.     uint8            *out    = (uint8 *)dst.data;
  1463.     const ptrdiff_t    opitch    = dst.pitch;
  1464.     const uint8        *yrow    = (const uint8 *)src.data;
  1465.     const uint8        *cbrow    = (const uint8 *)src.data2;
  1466.     const uint8        *crrow    = (const uint8 *)src.data3;
  1467.     const ptrdiff_t    ypitch    = src.pitch;
  1468.     const ptrdiff_t    cbpitch    = src.pitch2;
  1469.     const ptrdiff_t    crpitch    = src.pitch3;
  1470.  
  1471.     vdpixsize wpairs = (w-1)>>2;
  1472.     vdpixsize wleft = w - (wpairs<<2);
  1473.  
  1474.     do {
  1475.         uint8 *p = out;
  1476.         const uint8 *y = yrow;
  1477.         const uint8 *cb = cbrow;
  1478.         const uint8 *cr = crrow;
  1479.         vdpixsize wt;
  1480.  
  1481.         if (wpairs > 0) {
  1482.             wt = wpairs;
  1483.  
  1484.             do {
  1485.                 const unsigned cb0 = cb[0];
  1486.                 const unsigned cb1 = cb[1];
  1487.                 const unsigned cr0 = cr[0];
  1488.                 const unsigned cr1 = cr[1];
  1489.  
  1490.                 ycbcr_to_888(p+0, y[0], cb0, cr0);
  1491.                 ycbcr_to_888(p+3, y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2);
  1492.                 ycbcr_to_888(p+6, y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1);
  1493.                 ycbcr_to_888(p+9, y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2);
  1494.  
  1495.                 y += 4;
  1496.                 p += 12;
  1497.                 ++cb;
  1498.                 ++cr;
  1499.             } while(--wt);
  1500.         }
  1501.  
  1502.         if (wleft > 0) {
  1503.             wt = wleft;
  1504.  
  1505.             const uint8 cr0 = *cr;
  1506.             const uint8 cb0 = *cb;
  1507.  
  1508.             do {
  1509.                 ycbcr_to_888(p, *y++, cb0, cr0);
  1510.                 p += 4;
  1511.             } while(--wt);
  1512.         }
  1513.  
  1514.         vdptrstep(out, opitch);
  1515.         vdptrstep(yrow, ypitch);
  1516.         vdptrstep(cbrow, cbpitch);
  1517.         vdptrstep(crrow, crpitch);
  1518.     } while(--h);
  1519. }
  1520.  
  1521. DECLARE_YUV_PLANAR(YUV411, XRGB8888) {
  1522.     uint32            *out    = (uint32 *)dst.data;
  1523.     const ptrdiff_t    opitch    = dst.pitch;
  1524.     const uint8        *yrow    = (const uint8 *)src.data;
  1525.     const uint8        *cbrow    = (const uint8 *)src.data2;
  1526.     const uint8        *crrow    = (const uint8 *)src.data3;
  1527.     const ptrdiff_t    ypitch    = src.pitch;
  1528.     const ptrdiff_t    cbpitch    = src.pitch2;
  1529.     const ptrdiff_t    crpitch    = src.pitch3;
  1530.  
  1531.     vdpixsize wpairs = (w-1)>>2;
  1532.     vdpixsize wleft = w - (wpairs<<2);
  1533.  
  1534.     do {
  1535.         uint32 *p = out;
  1536.         const uint8 *y = yrow;
  1537.         const uint8 *cb = cbrow;
  1538.         const uint8 *cr = crrow;
  1539.         vdpixsize wt;
  1540.  
  1541.         if (wpairs > 0) {
  1542. #ifdef _M_AMD64
  1543.             wt = wpairs;
  1544.  
  1545.             do {
  1546.                 const unsigned cb0 = cb[0];
  1547.                 const unsigned cb1 = cb[1];
  1548.                 const unsigned cr0 = cr[0];
  1549.                 const unsigned cr1 = cr[1];
  1550.  
  1551.                 p[0] = ycbcr_to_8888(y[0], cb0, cr0);
  1552.                 p[1] = ycbcr_to_8888(y[1], (3*cb0+cb1+2)>>2, (3*cr0+cr1+2)>>2);
  1553.                 p[2] = ycbcr_to_8888(y[2], (cb0+cb1+1)>>1, (cr0+cr1+1)>>1);
  1554.                 p[3] = ycbcr_to_8888(y[3], (cb0+3*cb1+2)>>2, (cr0+3*cr1+2)>>2);
  1555.  
  1556.                 y += 4;
  1557.                 p += 4;
  1558.                 ++cb;
  1559.                 ++cr;
  1560.             } while(--wt);
  1561. #else
  1562.             vdasm_pixblt_YUV411Planar_to_XRGB8888_scan_MMX(p, y, cb, cr, wpairs);
  1563.             y += 4*wpairs;
  1564.             cr += wpairs;
  1565.             cb += wpairs;
  1566.             p += 4*wpairs;
  1567. #endif
  1568.         }
  1569.  
  1570.         if (wleft > 0) {
  1571.             wt = wleft;
  1572.  
  1573.             const uint8 cr0 = *cr;
  1574.             const uint8 cb0 = *cb;
  1575.  
  1576.             do {
  1577.                 *p++ = ycbcr_to_8888(*y++, cb0, cr0);
  1578.             } while(--wt);
  1579.         }
  1580.  
  1581.         vdptrstep(out, opitch);
  1582.         vdptrstep(yrow, ypitch);
  1583.         vdptrstep(cbrow, cbpitch);
  1584.         vdptrstep(crrow, crpitch);
  1585.     } while(--h);
  1586.  
  1587. #ifndef _M_AMD64
  1588.     __asm emms
  1589. #endif
  1590. }
  1591.