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 / stretchblt_reference.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  21.9 KB  |  817 lines

  1. #include <vd2/system/memory.h>
  2. #include <vd2/system/cpuaccel.h>
  3. #include <vd2/Kasumi/pixmap.h>
  4. #include <vd2/Kasumi/pixmaputils.h>
  5.  
  6. namespace {
  7.     struct VDPixmapReferenceStretchBltParameters {
  8.         void *dst;
  9.         ptrdiff_t    dstpitch;
  10.         const void *src;
  11.         ptrdiff_t    srcpitch;
  12.         ptrdiff_t    srcinc;
  13.         sint32        dx;
  14.         sint32        dy;
  15.         uint32        u;
  16.         uint32        uinc;
  17.         uint32        dudx;
  18.         uint32        v;
  19.         uint32        dvdy;
  20.         sint32        xprecopy;
  21.         sint32        xpostcopy;
  22.         ptrdiff_t    xprepos;
  23.         ptrdiff_t    xpostpos;
  24.  
  25.         void advance() {
  26.             dst = (char *)dst + dstpitch;
  27.             src = (char *)src + srcinc;
  28.  
  29.             uint32 vt = v + dvdy;
  30.  
  31.             if (vt < v)
  32.                 src = (char *)src + srcpitch;
  33.  
  34.             v = vt;
  35.         }
  36.     };
  37. }
  38.  
  39. void VDPixmapStretchBlt_Any8_nearest_reference(VDPixmapReferenceStretchBltParameters params) {
  40.     do {
  41.         uint8 *dstp = (uint8 *)params.dst;
  42.         const uint8 *srcp = (const uint8 *)params.src;
  43.         uint32 u = params.u;
  44.  
  45.         if (params.xprecopy) {
  46.             VDMemset8(dstp, *(const uint8 *)((const char *)params.src + params.xprepos), params.xprecopy);
  47.             dstp += params.xprecopy;
  48.         }
  49.  
  50.         sint32 wt = params.dx;
  51.  
  52.         if (wt > 0)
  53.             do {
  54.                 *dstp++ = *srcp;
  55.  
  56.                 uint32 ut = u + params.dudx;
  57.                 srcp += ut<u;
  58.                 srcp += params.uinc;
  59.                 u = ut;
  60.             } while(--wt);
  61.  
  62.         if (params.xpostcopy)
  63.             VDMemset8(dstp, *(const uint8 *)((const char *)params.src + params.xpostpos), params.xpostcopy);
  64.  
  65.         params.advance();
  66.     } while(--params.dy);
  67. }
  68.  
  69. void VDPixmapStretchBlt_Any16_nearest_reference(VDPixmapReferenceStretchBltParameters params) {
  70.     do {
  71.         uint16 *dstp = (uint16 *)params.dst;
  72.         const uint16 *srcp = (const uint16 *)params.src;
  73.         uint32 u = params.u;
  74.  
  75.         if (params.xprecopy) {
  76.             VDMemset16(dstp, *(const uint16 *)((const char *)params.src + params.xprepos), params.xprecopy);
  77.             dstp += params.xprecopy;
  78.         }
  79.  
  80.         sint32 wt = params.dx;
  81.  
  82.         if (wt > 0)
  83.             do {
  84.                 *dstp++ = *srcp;
  85.  
  86.                 uint32 ut = u + params.dudx;
  87.                 srcp += ut<u;
  88.                 srcp += params.uinc;
  89.                 u = ut;
  90.             } while(--wt);
  91.  
  92.         if (params.xpostcopy)
  93.             VDMemset16(dstp, *(const uint16 *)((const char *)params.src + params.xpostpos), params.xpostcopy);
  94.  
  95.         params.advance();
  96.     } while(--params.dy);
  97. }
  98.  
  99. void VDPixmapStretchBlt_Any24_nearest_reference(VDPixmapReferenceStretchBltParameters params) {
  100.     do {
  101.         uint8 *dstp = (uint8 *)params.dst;
  102.         const uint8 *srcp = (const uint8 *)params.src;
  103.         uint32 u = params.u;
  104.  
  105.         if (params.xprecopy) {
  106.             const uint8 *repsrc = (const uint8 *)params.src + params.xprepos;
  107.             const uint8 p0 = repsrc[0];
  108.             const uint8 p1 = repsrc[1];
  109.             const uint8 p2 = repsrc[2];
  110.  
  111.             for(sint32 i=0; i<params.xprecopy; ++i) {
  112.                 dstp[0] = p0;
  113.                 dstp[1] = p1;
  114.                 dstp[2] = p2;
  115.                 dstp += 3;
  116.             }
  117.         }
  118.  
  119.         sint32 wt = params.dx;
  120.  
  121.         if (wt > 0)
  122.             do {
  123.                 dstp[0] = srcp[0];
  124.                 dstp[1] = srcp[1];
  125.                 dstp[2] = srcp[2];
  126.                 dstp += 3;
  127.  
  128.                 uint32 ut = u + params.dudx;
  129.                 srcp += (ut<u)*3;
  130.                 srcp += params.uinc*3;
  131.                 u = ut;
  132.             } while(--wt);
  133.  
  134.         if (params.xpostcopy) {
  135.             const uint8 *repsrc = (const uint8 *)params.src + params.xpostpos;
  136.             const uint8 p0 = repsrc[0];
  137.             const uint8 p1 = repsrc[1];
  138.             const uint8 p2 = repsrc[2];
  139.  
  140.             for(sint32 i=0; i<params.xpostcopy; ++i) {
  141.                 dstp[0] = p0;
  142.                 dstp[1] = p1;
  143.                 dstp[2] = p2;
  144.                 dstp += 3;
  145.             }
  146.         }
  147.  
  148.         params.advance();
  149.     } while(--params.dy);
  150. }
  151.  
  152. void VDPixmapStretchBlt_Any32_nearest_reference(VDPixmapReferenceStretchBltParameters params) {
  153.     do {
  154.         uint32 *dstp = (uint32 *)params.dst;
  155.         const uint32 *srcp = (const uint32 *)params.src;
  156.         uint32 u = params.u;
  157.  
  158.         if (params.xprecopy) {
  159.             VDMemset32(dstp, *(const uint32 *)((const char *)params.src + params.xprepos), params.xprecopy);
  160.             dstp += params.xprecopy;
  161.         }
  162.  
  163.         sint32 wt = params.dx;
  164.         if (wt > 0)
  165.             do {
  166.                 *dstp++ = *srcp;
  167.  
  168.                 uint32 ut = u + params.dudx;
  169.                 srcp += ut<u;
  170.                 srcp += params.uinc;
  171.                 u = ut;
  172.             } while(--wt);
  173.  
  174.         if (params.xpostcopy)
  175.             VDMemset32(dstp, *(const uint32 *)((const char *)params.src + params.xpostpos), params.xpostcopy);
  176.  
  177.         params.advance();
  178.     } while(--params.dy);
  179. }
  180.  
  181. ///////////////////////////////////////////////////////////////////////////
  182.  
  183. namespace {
  184.     void VDSetupNearestSamplingParameters(sint64& u64, sint64 dudx, sint32 dx, sint32 du, sint32& xprecopy, sint32& xprepos, sint32& xmain, sint32& xpostcopy, sint32& xpostpos) {
  185.         sint64 ulo = u64;
  186.         sint64 uhi = u64 + dudx * (dx - 1);
  187.         sint64 tdudx = dudx;
  188.         const sint64 ulimit = ((sint64)du << 32);
  189.  
  190.         xprepos = 0;
  191.         xpostpos = du-1;
  192.  
  193.         if (!tdudx) {
  194.             if (u64 < 0)
  195.                 xprecopy = dx;
  196.             else if (u64 >= ulimit)
  197.                 xprecopy = dx;
  198.             else
  199.                 xmain = dx;
  200.         } else {
  201.             if (tdudx < 0) {
  202.                 std::swap(ulo, uhi);
  203.                 tdudx = -tdudx;
  204.             }
  205.  
  206.             if (ulo < 0) {
  207.                 if (uhi < 0)
  208.                     xprecopy = dx;
  209.                 else
  210.                     xprecopy = (sint32)((-ulo-1) / tdudx) + 1;
  211.  
  212.                 VDASSERT(xprecopy <= 0 || (uint64)ulo >= (uint64)ulimit);
  213.                 VDASSERT(xprecopy <= 0 || (uint64)(ulo + tdudx * (xprecopy-1)) >= (uint64)ulimit);
  214.             }
  215.  
  216.             if (uhi >= ulimit) {
  217.                 if (ulo >= ulimit)
  218.                     xpostcopy = dx;
  219.                 else
  220.                     xpostcopy = (sint32)((uhi - ulimit) / tdudx) + 1;
  221.  
  222.                 VDASSERT(xpostcopy <= 0 || (uint64)uhi >= (uint64)ulimit);
  223.                 VDASSERT(xpostcopy <= 0 || (uint64)(uhi - tdudx * (xpostcopy - 1)) >= (uint64)ulimit);
  224.             }
  225.  
  226.             if (dudx < 0) {
  227.                 std::swap(xprecopy, xpostcopy);
  228.                 std::swap(xprepos, xpostpos);
  229.             }
  230.  
  231.             xmain = dx - (xprecopy + xpostcopy);
  232.         }
  233.  
  234.         // sanity-check parameters
  235.  
  236.         VDASSERT(xprecopy>=0 && xprecopy <= dx);
  237.         VDASSERT(xpostcopy>=0 && xpostcopy <= dx);
  238.         VDASSERT(xmain>=0 && xmain <= dx);
  239.  
  240.         VDASSERT(xprecopy <= 0 || (uint64)u64 >= (uint64)ulimit);
  241.         VDASSERT(xprecopy <= 0 || (uint64)(u64 + dudx * (xprecopy-1)) >= (uint64)ulimit);
  242.         VDASSERT(xmain <= 0 || (uint64)(u64 + dudx * xprecopy) < (uint64)ulimit);
  243.         VDASSERT(xmain <= 0 || (uint64)(u64 + dudx * (xprecopy+xmain-1)) < (uint64)ulimit);
  244.         VDASSERT(xpostcopy <= 0 || (uint64)(u64 + dudx * (xprecopy + xmain)) >= (uint64)ulimit);
  245.         VDASSERT(xpostcopy <= 0 || (uint64)(u64 + dudx * (xprecopy + xmain + xpostcopy - 1)) >= (uint64)ulimit);
  246.  
  247.         u64 += dudx * xprecopy;
  248.     }
  249. }
  250.  
  251. bool VDPixmapStretchBltNearest_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) {
  252.     // we don't support format conversion
  253.     if (dst.format != src.format)
  254.         return false;
  255.  
  256.     void (*pBlitter)(VDPixmapReferenceStretchBltParameters);
  257.     int bpp;
  258.  
  259.     switch(src.format) {
  260.     case nsVDPixmap::kPixFormat_Pal8:
  261.         pBlitter = VDPixmapStretchBlt_Any8_nearest_reference;
  262.         bpp = 1;
  263.         break;
  264.     case nsVDPixmap::kPixFormat_XRGB1555:
  265.     case nsVDPixmap::kPixFormat_RGB565:
  266.         pBlitter = VDPixmapStretchBlt_Any16_nearest_reference;
  267.         bpp = 2;
  268.         break;
  269.     case nsVDPixmap::kPixFormat_RGB888:
  270.         pBlitter = VDPixmapStretchBlt_Any24_nearest_reference;
  271.         bpp = 3;
  272.         break;
  273.     case nsVDPixmap::kPixFormat_XRGB8888:
  274.         pBlitter = VDPixmapStretchBlt_Any32_nearest_reference;
  275.         bpp = 4;
  276.         break;
  277.     default:
  278.         return false;
  279.     }
  280.  
  281.     // preemptive clip to prevent gradient calculations from crashing
  282.     if (x2 == x1 || y2 == y1)
  283.         return true;
  284.  
  285.     // translate destination flips into source flips
  286.     if (x1 > x2) {
  287.         std::swap(x1, x2);
  288.         std::swap(u1, u2);
  289.     }
  290.  
  291.     if (y1 > y2) {
  292.         std::swap(y1, y2);
  293.         std::swap(v1, v2);
  294.     }
  295.  
  296.     // compute gradients
  297.     sint32 dx    = x2 - x1;
  298.     sint32 dy    = y2 - y1;
  299.     sint32 du    = u2 - u1;
  300.     sint32 dv    = v2 - v1;
  301.     sint64 dudx = ((sint64)du << 32) / dx;        // must truncate toward zero to prevent overflow
  302.     sint64 dvdy = ((sint64)dv << 32) / dy;
  303.  
  304.     // prestep top-left point to pixel center and convert destination coordinates to integer
  305.     sint64 u64 = (sint64)u1 << 16;
  306.     sint64 v64 = (sint64)v1 << 16;
  307.     sint32 prestepx = (0x8000 - x1) & 0xffff;
  308.     sint32 prestepy = (0x8000 - y1) & 0xffff;
  309.  
  310.     u64 += (dudx * prestepx) >> 16;
  311.     v64 += (dvdy * prestepy) >> 16;
  312.  
  313.     sint32 x1i = (x1 + 0x8000) >> 16;
  314.     sint32 y1i = (y1 + 0x8000) >> 16;
  315.     sint32 x2i = (x2 + 0x8000) >> 16;
  316.     sint32 y2i = (y2 + 0x8000) >> 16;
  317.  
  318.     // destination clipping
  319.     if (x1i < 0) {
  320.         u64 -= dudx * x1i;
  321.         x1i = 0;
  322.     }
  323.  
  324.     if (y1i < 0) {
  325.         v64 -= dvdy * y1i;
  326.         y1i = 0;
  327.     }
  328.  
  329.     if (x2i > dst.w)
  330.         x2i = dst.w;
  331.  
  332.     if (y2i > dst.h)
  333.         y2i = dst.h;
  334.  
  335.     if (x1i >= x2i || y1i >= y2i)
  336.         return true;
  337.  
  338.     // Calculate horizontal clip parameters
  339.     sint32 xprecopy = 0, xpostcopy = 0;
  340.     int xprepos = 0;
  341.     int xpostpos = src.w-1;
  342.     int xmain = 0;
  343.  
  344.     VDSetupNearestSamplingParameters(u64, dudx, x2i-x1i, src.w, xprecopy, xprepos, xmain, xpostcopy, xpostpos);
  345.  
  346.     // Calculate vertical clip parameters
  347.     sint32 yprecopy = 0, ypostcopy = 0;
  348.     int yprepos = 0;
  349.     int ypostpos = src.h-1;
  350.     int ymain = 0;
  351.  
  352.     VDSetupNearestSamplingParameters(v64, dvdy, y2i-y1i, src.h, yprecopy, yprepos, ymain, ypostcopy, ypostpos);
  353.  
  354.     // set up parameter block
  355.     VDPixmapReferenceStretchBltParameters params;
  356.  
  357.     char *srcbase = (char *)src.data + (sint32)(u64 >> 32) * bpp;
  358.  
  359.     params.dst            = (char *)dst.data + y1i * dst.pitch + x1i * bpp;
  360.     params.dstpitch        = dst.pitch;
  361.     params.src            = srcbase + (sint32)(v64 >> 32) * src.pitch;
  362.     params.srcpitch        = src.pitch;
  363.     params.srcinc        = (sint32)(dvdy >> 32) * src.pitch;
  364.     params.dx            = xmain;
  365.     params.dy            = ymain;
  366.     params.u            = (uint32)u64;
  367.     params.uinc            = (uint32)(dudx >> 32);
  368.     params.dudx            = (uint32)dudx;
  369.     params.v            = (uint32)v64;
  370.     params.dvdy            = (uint32)dvdy;
  371.     params.xprecopy        = xprecopy;
  372.     params.xprepos        = (xprepos - (sint32)(u64 >> 32)) * bpp;
  373.     params.xpostcopy    = xpostcopy;
  374.     params.xpostpos        = (xpostpos - (sint32)(u64 >> 32)) * bpp;
  375.  
  376.     if (yprecopy > 0) {
  377.         VDPixmapReferenceStretchBltParameters preparams(params);
  378.  
  379.         preparams.src        = srcbase + yprepos * src.pitch;
  380.         preparams.srcinc    = 0;
  381.         preparams.dy        = yprecopy;
  382.         preparams.v            = 0;
  383.         preparams.dvdy        = 0;
  384.  
  385.         pBlitter(preparams);
  386.  
  387.         params.dst        = (char *)params.dst + params.dstpitch * yprecopy;
  388.     }
  389.  
  390.     if (ymain > 0)
  391.         pBlitter(params);
  392.  
  393.     if (ypostcopy > 0) {
  394.         VDPixmapReferenceStretchBltParameters postparams(params);
  395.  
  396.         postparams.dst        = (char *)params.dst + params.dstpitch * params.dy;
  397.         postparams.src        = srcbase + ypostpos * src.pitch;
  398.         postparams.srcpitch    = 0;
  399.         postparams.srcinc    = 0;
  400.         postparams.dy        = ypostcopy;
  401.         postparams.v        = 0;
  402.         postparams.dvdy        = 0;
  403.  
  404.         pBlitter(postparams);
  405.     }
  406.     return true;
  407. }
  408.  
  409. /////////////////////////////////////////////////////////////////////////////////////////////////
  410.  
  411. namespace {
  412.     uint32 lerp_XRGB1555(sint32 a, sint32 b, sint32 f) {
  413.         sint32 a_rb    = a & 0x7c1f;
  414.         sint32 a_g    = a & 0x03e0;
  415.         sint32 b_rb    = b & 0x7c1f;
  416.         sint32 b_g    = b & 0x03e0;
  417.  
  418.         const sint32 rb = (a_rb + (((b_rb - a_rb)*f + 0x4010) >> 5)) & 0x7c1f;
  419.         const sint32 g  = (a_g  + (((b_g  - a_g )*f + 0x0200) >> 5)) & 0x03e0;
  420.  
  421.         return rb + g;
  422.     }
  423.  
  424.     uint32 lerp_XRGB8888(sint32 a, sint32 b, sint32 f) {
  425.         sint32 a_rb    = a & 0xff00ff;
  426.         sint32 a_g    = a & 0x00ff00;
  427.         sint32 b_rb    = b & 0xff00ff;
  428.         sint32 b_g    = b & 0x00ff00;
  429.  
  430.         const uint32 rb = (a_rb + (((b_rb - a_rb)*f + 0x00800080) >> 8)) & 0xff00ff;
  431.         const uint32 g  = (a_g  + (((b_g  - a_g )*f + 0x00008000) >> 8)) & 0x00ff00;
  432.  
  433.         return rb + g;
  434.     }
  435.  
  436.     uint32 bilerp_RGB888(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) {
  437.         sint32 a_rb    = a & 0xff00ff;
  438.         sint32 a_g    = a & 0x00ff00;
  439.         sint32 b_rb    = b & 0xff00ff;
  440.         sint32 b_g    = b & 0x00ff00;
  441.         sint32 c_rb    = c & 0xff00ff;
  442.         sint32 c_g    = c & 0x00ff00;
  443.         sint32 d_rb    = d & 0xff00ff;
  444.         sint32 d_g    = d & 0x00ff00;
  445.  
  446.         const uint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x00800080) >> 8)) & 0xff00ff;
  447.         const uint32 top_g  = (a_g  + (((b_g  - a_g )*x + 0x00008000) >> 8)) & 0x00ff00;
  448.         const uint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x00800080) >> 8)) & 0xff00ff;
  449.         const uint32 bot_g  = (c_g  + (((d_g  - c_g )*x + 0x00008000) >> 8)) & 0x00ff00;
  450.  
  451.         const uint32 final_rb = (top_rb + (((bot_rb - top_rb)*y) >> 8)) & 0xff00ff;
  452.         const uint32 final_g  = (top_g  + (((bot_g  - top_g )*y) >> 8)) & 0x00ff00;
  453.  
  454.         return final_rb + final_g;
  455.     }
  456.  
  457.     uint32 bilerp_XRGB1555(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) {
  458.         sint32 a_rb    = a & 0x7c1f;
  459.         sint32 a_g    = a & 0x03e0;
  460.         sint32 b_rb    = b & 0x7c1f;
  461.         sint32 b_g    = b & 0x03e0;
  462.         sint32 c_rb    = c & 0x7c1f;
  463.         sint32 c_g    = c & 0x03e0;
  464.         sint32 d_rb    = d & 0x7c1f;
  465.         sint32 d_g    = d & 0x03e0;
  466.  
  467.         const sint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x4010) >> 5)) & 0x7c1f;
  468.         const sint32 top_g  = (a_g  + (((b_g  - a_g )*x + 0x0200) >> 5)) & 0x03e0;
  469.         const sint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x4010) >> 5)) & 0x7c1f;
  470.         const sint32 bot_g  = (c_g  + (((d_g  - c_g )*x + 0x0200) >> 5)) & 0x03e0;
  471.  
  472.         const sint32 final_rb = (top_rb + (((bot_rb - top_rb)*y + 0x4010) >> 5)) & 0x7c1f;
  473.         const sint32 final_g  = (top_g  + (((bot_g  - top_g )*y + 0x0200) >> 5)) & 0x03e0;
  474.  
  475.         return final_rb + final_g;
  476.     }
  477.  
  478.     uint32 bilerp_RGB565(sint32 a, sint32 b, sint32 c, sint32 d, sint32 x, sint32 y) {
  479.         sint32 a_rb    = a & 0xf81f;
  480.         sint32 a_g    = a & 0x07e0;
  481.         sint32 b_rb    = b & 0xf81f;
  482.         sint32 b_g    = b & 0x07e0;
  483.         sint32 c_rb    = c & 0xf81f;
  484.         sint32 c_g    = c & 0x07e0;
  485.         sint32 d_rb    = d & 0xf81f;
  486.         sint32 d_g    = d & 0x07e0;
  487.  
  488.         const sint32 top_rb = (a_rb + (((b_rb - a_rb)*x + 0x8010) >> 6)) & 0xf81f;
  489.         const sint32 top_g  = (a_g  + (((b_g  - a_g )*x + 0x0400) >> 6)) & 0x07e0;
  490.         const sint32 bot_rb = (c_rb + (((d_rb - c_rb)*x + 0x8010) >> 6)) & 0xf81f;
  491.         const sint32 bot_g  = (c_g  + (((d_g  - c_g )*x + 0x0400) >> 6)) & 0x07e0;
  492.  
  493.         const sint32 final_rb = (top_rb + (((bot_rb - top_rb)*y + 0x8010) >> 6)) & 0xf81f;
  494.         const sint32 final_g  = (top_g  + (((bot_g  - top_g )*y + 0x0400) >> 6)) & 0x07e0;
  495.  
  496.         return final_rb + final_g;
  497.     }
  498. }
  499.  
  500. ///////////////////////////////////////////////////////////////////////////
  501.  
  502. namespace {
  503.     struct VDPixmapReferenceStretchBltBilinearParameters {
  504.         void        *dst;
  505.         const void    *src;
  506.         uint32        u;
  507.         uint32        uinc;
  508.         uint32        dudx;
  509.  
  510.         ptrdiff_t    xprepos;
  511.         ptrdiff_t    xpostpos;
  512.         sint32        xprecopy;
  513.         sint32        xpostcopy;
  514.         sint32        xmidsize;
  515.     };
  516.  
  517.     void VDPixmapStretchBiH_XRGB1555_to_XRGB1555(const VDPixmapReferenceStretchBltBilinearParameters& params) {
  518.         uint16 *dst = (uint16 *)params.dst;
  519.         const uint16 *src = (const uint16 *)params.src;
  520.  
  521.         if (params.xprecopy)
  522.             VDMemset16(dst - params.xprecopy, *(const uint16 *)((const char *)params.src + params.xprepos), params.xprecopy);
  523.  
  524.         if (params.xmidsize) {
  525.             sint32 w = params.xmidsize;
  526.             uint32 u = params.u;
  527.             const uint32 dudx = params.dudx;
  528.             const ptrdiff_t uinc = params.uinc;
  529.  
  530.             do {
  531.                 *dst++ = lerp_XRGB1555(src[0], src[1], u >> 27);
  532.  
  533.                 const uint32 ut = u + dudx;
  534.                 src += uinc + (ut < u);
  535.                 u = ut;
  536.             } while(--w);
  537.         }
  538.  
  539.         if (params.xpostcopy)
  540.             VDMemset16(dst, *(const uint16 *)((const char *)params.src + params.xpostpos), params.xpostcopy);
  541.     }
  542.  
  543.     void VDPixmapStretchBiH_XRGB8888_to_XRGB8888(const VDPixmapReferenceStretchBltBilinearParameters& params) {
  544.         uint32 *dst = (uint32 *)params.dst;
  545.         const uint32 *src = (const uint32 *)params.src;
  546.  
  547.         if (params.xprecopy)
  548.             VDMemset32(dst - params.xprecopy, *(const uint32 *)((const char *)params.src + params.xprepos), params.xprecopy);
  549.  
  550.         if (params.xmidsize) {
  551.             sint32 w = params.xmidsize;
  552.             uint32 u = params.u;
  553.             const uint32 dudx = params.dudx;
  554.             const ptrdiff_t uinc = params.uinc;
  555.  
  556.             do {
  557.                 *dst++ = lerp_XRGB8888(src[0], src[1], u >> 24);
  558.  
  559.                 const uint32 ut = u + dudx;
  560.                 src += uinc + (ut < u);
  561.                 u = ut;
  562.             } while(--w);
  563.         }
  564.  
  565.         if (params.xpostcopy)
  566.             VDMemset32(dst, *(const uint32 *)((const char *)params.src + params.xpostpos), params.xpostcopy);
  567.     }
  568.  
  569.     void VDPixmapStretchBiV_XRGB1555_to_XRGB1555(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f) {
  570.         uint16 *dst = (uint16 *)dstv;
  571.         const uint16 *src1 = (const uint16 *)src1v;
  572.         const uint16 *src2 = (const uint16 *)src2v;
  573.  
  574.         f >>= 27;
  575.  
  576.         do {
  577.             *dst++ = lerp_XRGB1555(*src1++, *src2++, f);
  578.         } while(--w);
  579.     }
  580.  
  581.     void VDPixmapStretchBiV_XRGB8888_to_XRGB8888(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f) {
  582.         uint32 *dst = (uint32 *)dstv;
  583.         const uint32 *src1 = (const uint32 *)src1v;
  584.         const uint32 *src2 = (const uint32 *)src2v;
  585.  
  586.         f >>= 24;
  587.  
  588.         do {
  589.             *dst++ = lerp_XRGB8888(*src1++, *src2++, f);
  590.         } while(--w);
  591.     }
  592. }
  593.  
  594. #ifdef _M_IX86
  595. extern "C" void vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX(const VDPixmapReferenceStretchBltBilinearParameters&);
  596.  
  597. extern "C" void vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f);
  598. extern "C" void vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f);
  599. #endif
  600.  
  601. bool VDPixmapStretchBltBilinear_reference(const VDPixmap& dst, sint32 x1, sint32 y1, sint32 x2, sint32 y2, const VDPixmap& src, sint32 u1, sint32 v1, sint32 u2, sint32 v2) {
  602.     // preemptive clip to prevent gradient calculations from crashing
  603.     if (x2 == x1 || y2 == y1)
  604.         return true;
  605.  
  606.     // we don't support source clipping
  607.     if ((uint32)u1 > (uint32)(src.w << 16) || (uint32)v1 > (uint32)(src.h << 16))
  608.         return false;
  609.  
  610.     if ((uint32)u2 > (uint32)(src.w << 16) || (uint32)v2 > (uint32)(src.h << 16))
  611.         return false;
  612.  
  613.     // we don't support format changes (yet)
  614.     if (dst.format != src.format)
  615.         return false;
  616.  
  617.     // format determination
  618.     void (*pHorizontalFilter)(const VDPixmapReferenceStretchBltBilinearParameters& params);
  619.     void (*pVerticalFilter)(void *dstv, const void *src1v, const void *src2v, sint32 w, uint32 f);
  620.     int bpp;
  621.  
  622. #pragma vdpragma_TODO("fixme this is b0rken")
  623.     switch(src.format) {
  624.     case nsVDPixmap::kPixFormat_XRGB1555:
  625.         pHorizontalFilter = VDPixmapStretchBiH_XRGB1555_to_XRGB1555;
  626. #ifdef _M_IX86
  627.         if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX)
  628.             pVerticalFilter = vdasm_stretchbltV_XRGB1555_to_XRGB1555_MMX;
  629.         else
  630. #endif
  631.             pVerticalFilter = VDPixmapStretchBiV_XRGB1555_to_XRGB1555;
  632.         bpp = 2;
  633.         break;
  634.     case nsVDPixmap::kPixFormat_XRGB8888:
  635. #ifdef _M_IX86
  636.         if (CPUGetEnabledExtensions() & CPUF_SUPPORTS_MMX) {
  637.             pHorizontalFilter = vdasm_stretchbltH_XRGB8888_to_XRGB8888_MMX;
  638.             pVerticalFilter = vdasm_stretchbltV_XRGB8888_to_XRGB8888_MMX;
  639.         } else
  640. #endif
  641.         {
  642.             pHorizontalFilter = VDPixmapStretchBiH_XRGB8888_to_XRGB8888;
  643.             pVerticalFilter = VDPixmapStretchBiV_XRGB8888_to_XRGB8888;
  644.         }
  645.         bpp = 4;
  646.         break;
  647.     default:
  648.         return false;
  649.     }
  650.  
  651.     // translate destination flips into source flips
  652.     if (x1 > x2) {
  653.         std::swap(x1, x2);
  654.         std::swap(u1, u2);
  655.     }
  656.  
  657.     if (y1 > y2) {
  658.         std::swap(y1, y2);
  659.         std::swap(v1, v2);
  660.     }
  661.  
  662.     // compute gradients
  663.     sint32 dx    = x2 - x1;
  664.     sint32 dy    = y2 - y1;
  665.     sint32 du    = u2 - u1;
  666.     sint32 dv    = v2 - v1;
  667.     sint64 dudx = ((sint64)du << 32) / dx;        // must truncate toward zero to prevent overflow
  668.     sint64 dvdy = ((sint64)dv << 32) / dy;
  669.  
  670.     // prestep top-left point to pixel center and convert destination coordinates to integer
  671.     sint64 u64 = (sint64)u1 << 16;
  672.     sint64 v64 = (sint64)v1 << 16;
  673.     sint32 prestepx = (0x8000 - x1) & 0xffff;
  674.     sint32 prestepy = (0x8000 - y1) & 0xffff;
  675.  
  676.     u64 += (dudx * prestepx) >> 16;
  677.     v64 += (dvdy * prestepy) >> 16;
  678.  
  679.     sint32 x1i = (x1 + 0x8000) >> 16;
  680.     sint32 y1i = (y1 + 0x8000) >> 16;
  681.     sint32 x2i = (x2 + 0x8000) >> 16;
  682.     sint32 y2i = (y2 + 0x8000) >> 16;
  683.  
  684.     // destination clipping
  685.     if (x1i < 0) {
  686.         u64 -= dudx * x1i;
  687.         x1i = 0;
  688.     }
  689.  
  690.     if (y1i < 0) {
  691.         v64 -= dvdy * y1i;
  692.         y1i = 0;
  693.     }
  694.  
  695.     if (x2i > dst.w)
  696.         x2i = dst.w;
  697.  
  698.     if (y2i > dst.h)
  699.         y2i = dst.h;
  700.  
  701.     if (x1i >= x2i || y1i >= y2i)
  702.         return true;
  703.  
  704.     u64 -= 0x80000000;
  705.     v64 -= 0x80000000;
  706.  
  707.     int xprepos = 0;
  708.     int xpostpos = src.w-1;
  709.  
  710.     sint64 ulo = u64;
  711.     sint64 uhi = u64 + dudx * (x2i - x1i - 1);
  712.     sint64 tdudx = dudx;
  713.  
  714.     if (ulo > uhi) {
  715.         std::swap(ulo, uhi);
  716.         tdudx = -tdudx;
  717.     }
  718.  
  719.     int xprecopy = 0;
  720.     int xpostcopy = 0;
  721.  
  722.     if (ulo < 0) {
  723.         xprecopy = (int)((1 - ulo) / tdudx) + 1;
  724.     }
  725.  
  726.     const sint64 ulimit = ((sint64)(src.w-1) << 32);
  727.  
  728.     if (uhi >= ulimit)
  729.         xpostcopy = (int)((uhi - ulimit - 1) / tdudx) + 1;
  730.  
  731.     if (dudx < 0) {
  732.         std::swap(xprecopy, xpostcopy);
  733.         std::swap(xprepos, xpostpos);
  734.     }
  735.  
  736.     u64 += dudx * xprecopy;
  737.     const int xtotal    = x2i - x1i;
  738.     int xmidcopy = (x2i - x1i) - (xprecopy + xpostcopy);
  739.     const sint32 ui = (sint32)(u64 >> 32);
  740.  
  741.     // set up parameter block
  742.  
  743.     VDPixmapReferenceStretchBltBilinearParameters params;
  744.  
  745.     params.u            = (uint32)u64;
  746.     params.uinc            = (sint32)(dudx >> 32);
  747.     params.dudx            = (sint32)dudx;
  748.     params.xprecopy        = xprecopy;
  749.     params.xprepos        = (xprepos - ui) * bpp;
  750.     params.xpostcopy    = xpostcopy;
  751.     params.xpostpos        = (xpostpos - ui) * bpp;
  752.     params.xmidsize        = xmidcopy;
  753.  
  754.     void *dstp            = (char *)dst.data + y1i * dst.pitch + x1i * bpp;
  755.     const void *srcp    = (char *)src.data + ui * bpp;
  756.  
  757.     VDPixmapBuffer        window(xtotal, 2, src.format);
  758.  
  759.     void *pTempRow1 = window.data;
  760.     void *pTempRow2 = (char *)window.data + window.pitch;
  761.     int windowbottom = dvdy > 0 ? -0x7fffffff : 0x7fffffff;
  762.  
  763.     do {
  764.         sint32 iv = (sint32)(v64 >> 32);
  765.         sint32 iv_bottom = iv + 1;
  766.  
  767.         if (iv < 0)
  768.             iv = iv_bottom = 0;
  769.  
  770.         if (iv >= src.h-1)
  771.             iv = iv_bottom = src.h-1;
  772.  
  773.         if (dvdy < 0) {
  774.             if (windowbottom > iv_bottom+1)
  775.                 windowbottom = iv_bottom+1;
  776.  
  777.             while(windowbottom > iv) {
  778.                 std::swap(pTempRow1, pTempRow2);
  779.  
  780.                 --windowbottom;
  781.  
  782.                 params.dst        = (char *)pTempRow1 + bpp * params.xprecopy;
  783.                 params.src        = vdptroffset(srcp, windowbottom * src.pitch);
  784.  
  785.                 pHorizontalFilter(params);
  786.             }
  787.         } else {
  788.             if (windowbottom < iv-1)
  789.                 windowbottom = iv-1;
  790.  
  791.             while(windowbottom < iv_bottom) {
  792.                 std::swap(pTempRow1, pTempRow2);
  793.  
  794.                 ++windowbottom;
  795.  
  796.                 params.dst        = (char *)pTempRow2 + bpp * params.xprecopy;
  797.                 params.src        = vdptroffset(srcp, windowbottom * src.pitch);
  798.  
  799.                 pHorizontalFilter(params);
  800.             }
  801.         }
  802.  
  803.         if (iv == iv_bottom)
  804.             if (dvdy < 0)
  805.                 pVerticalFilter(dstp, pTempRow1, pTempRow1, xtotal, 0);
  806.             else
  807.                 pVerticalFilter(dstp, pTempRow2, pTempRow2, xtotal, 0);
  808.         else
  809.             pVerticalFilter(dstp, pTempRow1, pTempRow2, xtotal, (uint32)v64);
  810.  
  811.         v64 += dvdy;
  812.         dstp = (char *)dstp + dst.pitch;
  813.     } while(++y1i < y2i);
  814.  
  815.     return true;
  816. }
  817.