Advertisement
Guest User

Untitled

a guest
Mar 6th, 2012
104
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 80.90 KB | None | 0 0
  1. // Avisynth v2.5.  Copyright 2002 Ben Rudiak-Gould et al.
  2. // http://www.avisynth.org
  3.  
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; either version 2 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program; if not, write to the Free Software
  16. // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit
  17. // http://www.gnu.org/copyleft/gpl.html .
  18. //
  19. // Linking Avisynth statically or dynamically with other modules is making a
  20. // combined work based on Avisynth.  Thus, the terms and conditions of the GNU
  21. // General Public License cover the whole combination.
  22. //
  23. // As a special exception, the copyright holders of Avisynth give you
  24. // permission to link Avisynth with independent modules that communicate with
  25. // Avisynth solely through the interfaces defined in avisynth.h, regardless of the license
  26. // terms of these independent modules, and to copy and distribute the
  27. // resulting combined work under terms of your choice, provided that
  28. // every copy of the combined work is accompanied by a complete copy of
  29. // the source code of Avisynth (the version of Avisynth used to produce the
  30. // combined work), being distributed under the terms of the GNU General
  31. // Public License plus this exception.  An independent module is a module
  32. // which is not derived from or based on Avisynth, such as 3rd-party filters,
  33. // import and export plugins, or graphical user interfaces.
  34.  
  35. #include "stdafx.h"
  36.  
  37. #include "resample.h"
  38.  
  39.  
  40.  
  41.  
  42. /********************************************************************
  43. ***** Declare index of new filters for Avisynth's filter engine *****
  44. ********************************************************************/
  45.  
  46. extern const AVSFunction Resample_filters[] = {
  47.   { "PointResize", "cii[src_left]f[src_top]f[src_width]f[src_height]f", FilteredResize::Create_PointResize },
  48.   { "BilinearResize", "cii[src_left]f[src_top]f[src_width]f[src_height]f", FilteredResize::Create_BilinearResize },
  49.   { "BicubicResize", "cii[b]f[c]f[src_left]f[src_top]f[src_width]f[src_height]f", FilteredResize::Create_BicubicResize },
  50.   { "LanczosResize", "cii[src_left]f[src_top]f[src_width]f[src_height]f[taps]i", FilteredResize::Create_LanczosResize},
  51.   { "Lanczos4Resize", "cii[src_left]f[src_top]f[src_width]f[src_height]f", FilteredResize::Create_Lanczos4Resize},
  52.   { "BlackmanResize", "cii[src_left]f[src_top]f[src_width]f[src_height]f[taps]i", FilteredResize::Create_BlackmanResize},
  53.   { "Spline16Resize", "cii[src_left]f[src_top]f[src_width]f[src_height]f", FilteredResize::Create_Spline16Resize},
  54.   { "Spline36Resize", "cii[src_left]f[src_top]f[src_width]f[src_height]f", FilteredResize::Create_Spline36Resize},
  55.   { "Spline64Resize", "cii[src_left]f[src_top]f[src_width]f[src_height]f", FilteredResize::Create_Spline64Resize},
  56.   { "GaussResize", "cii[src_left]f[src_top]f[src_width]f[src_height]f[p]f", FilteredResize::Create_GaussianResize},
  57.   { "SincResize", "cii[src_left]f[src_top]f[src_width]f[src_height]f[taps]i", FilteredResize::Create_SincResize},
  58.   /**
  59.     * Resize(PClip clip, dst_width, dst_height [src_left, src_top, src_width, int src_height,] )
  60.     *
  61.     * src_left et al.   =  when these optional arguments are given, the filter acts just like
  62.     *                      a Crop was performed with those parameters before resizing, only faster
  63.    **/
  64.  
  65.   { 0 }
  66. };
  67.  
  68.  
  69.  
  70.  
  71.  
  72. /****************************************
  73.  ***** Filtered Resize - Horizontal *****
  74.  ***************************************/
  75.  
  76. FilteredResizeH::FilteredResizeH( PClip _child, double subrange_left, double subrange_width,
  77.                                   int target_width, ResamplingFunction* func, IScriptEnvironment* env )
  78.   : GenericVideoFilter(_child), tempY(0), tempUV(0),pattern_luma(0),pattern_chroma(0)
  79. {
  80.     try {   // HIDE DAMN SEH COMPILER BUG!!!
  81.  
  82.   original_width = vi.width;
  83.  
  84.   if (target_width<=0)
  85.     env->ThrowError("Resize: Width must be greater than 0.");
  86.  
  87.   if (vi.IsYUV()) {
  88.     if (vi.IsYUY2()) {
  89.       if (target_width&1)
  90.         env->ThrowError("Resize: YUY2 destination width must be even");
  91.  
  92.       tempUV = (BYTE*) _aligned_malloc(original_width*4+8+32, 64);  // aligned for cache line
  93.     }
  94.     else if (vi.IsPlanar() && !vi.IsY8()) {
  95.       const int mask = (1 << vi.GetPlaneWidthSubsampling(PLANAR_U)) - 1;
  96.  
  97.       if (target_width & mask)
  98.         env->ThrowError("Resize: Planar destination width must be a multiple of %d.", mask+1);
  99.     }
  100.  
  101.     tempY = (BYTE*) _aligned_malloc(original_width*2+4+32, 64);   // aligned for cache line
  102.  
  103.     if (vi.IsYUY2()) {
  104.       pattern_chroma = func->GetResamplingPatternYUV(
  105.                                           vi.width       >> 1,
  106.                                           subrange_left  /  2,
  107.                                           subrange_width /  2,
  108.                                           target_width   >> 1,
  109.                                           false, tempUV, env );
  110.     }
  111.     else if (vi.IsPlanar() && !vi.IsY8()) {
  112.       const int shift = vi.GetPlaneWidthSubsampling(PLANAR_U);
  113.       const int div   = 1 << shift;
  114.  
  115.       pattern_chroma = func->GetResamplingPatternYUV(
  116.                                           vi.width       >> shift,
  117.                                           subrange_left  /  div,
  118.                                           subrange_width /  div,
  119.                                           target_width   >> shift,
  120.                                           true, tempY, env );
  121.     }
  122.  
  123.     pattern_luma = func->GetResamplingPatternYUV(vi.width, subrange_left, subrange_width, target_width, true, tempY, env);
  124.   }
  125.   else
  126.     pattern_luma = func->GetResamplingPatternRGB(vi.width, subrange_left, subrange_width, target_width, env);
  127.  
  128.   vi.width = target_width;
  129.  
  130.   if (vi.IsPlanar()) {
  131.     try {
  132.       assemblerY         = GenerateResizer(PLANAR_Y, false, env);
  133.       assemblerY_aligned = GenerateResizer(PLANAR_Y, true,  env);
  134.       if (!vi.IsY8()) {
  135.         assemblerUV         = GenerateResizer(PLANAR_U, false, env);
  136.         assemblerUV_aligned = GenerateResizer(PLANAR_U, true,  env);
  137.       }
  138.     }
  139.     catch (SoftWire::Error err) {
  140.        env->ThrowError("Resize: SoftWire exception : %s", err.getString());
  141.     }
  142.   }
  143.     }   catch (...) { throw; }
  144. }
  145.  
  146. /***********************************
  147.  * Dynamically Assembled Resampler
  148.  *
  149.  * (c) 2003, Klaus Post
  150.  * (c) 2009, Ian Brabham
  151.  *
  152.  * Dynamic version of the Horizontal resizer
  153.  *
  154.  * The Algorithm is the same, except this
  155.  *  one is able to process 6 pixels in parallel.
  156.  * The inner loop filter is unrolled based on the
  157.  *  exact filter size.
  158.  * Too much code to workaround for the 6 pixels, and
  159.  *  still not quite perfect. Though still faster than
  160.  *  the original code.
  161.  * New SSE2 unpacker does 64 bytes per cycle, many times
  162.  *  faster, contributes approx +5% to overall speed.
  163.  *
  164.  * :TODO: SSE2 version of main code
  165.  **********************************/
  166.  
  167.  
  168.  
  169. DynamicAssembledCode FilteredResizeH::GenerateResizer(int gen_plane, bool source_aligned, IScriptEnvironment* env) {
  170.   __declspec(align(8)) static const __int64 FPround       = 0x0000200000002000; // 16384/2
  171.   __declspec(align(8)) static const __int64 Mask2_pix     = 0x000000000000ffff;
  172.   __declspec(align(8)) static const __int64 Mask1_pix_inv = 0xffffffffffffff00;
  173.   __declspec(align(8)) static const __int64 Mask2_pix_inv = 0xffffffffffff0000;
  174.   __declspec(align(8)) static const __int64 Mask3_pix_inv = 0xffffffffff000000;
  175.  
  176.   Assembler x86;   // This is the class that assembles the code.
  177.  
  178.   // Set up variables for this plane.
  179.   int vi_height = vi.height >> vi.GetPlaneHeightSubsampling(gen_plane);
  180.   int vi_dst_width = vi.width >> vi.GetPlaneWidthSubsampling(gen_plane);
  181.   int vi_src_width = original_width >> vi.GetPlaneWidthSubsampling(gen_plane);
  182.  
  183.   int mod16_w = ((3+vi_src_width)/16);  // Src size!
  184.   int mod16_remain = (3+vi_src_width-(mod16_w*16))/4;  //Src size!
  185.  
  186.   bool isse = !!(env->GetCPUFlags() & CPUF_INTEGER_SSE);
  187.   bool sse2 = !!(env->GetCPUFlags() & CPUF_SSE2);
  188.   bool sse3 = !!(env->GetCPUFlags() & CPUF_SSE3);
  189.   bool sse4 = !!(env->GetCPUFlags() & CPUF_SSE4);
  190.  
  191.   if (source_aligned && !sse2) // No fast aligned version without SSE2+
  192.     return DynamicAssembledCode();
  193.  
  194.   int prefetchevery = 2;
  195.   if ((env->GetCPUFlags() & CPUF_3DNOW_EXT)||((env->GetCPUFlags() & CPUF_SSE2))) {
  196.     // We have either an Athlon or a P4 with 64byte cacheline
  197.     prefetchevery = 4;
  198.   }
  199.  
  200.   bool unroll_fetch = false;
  201.   // Unroll fetch loop on Athlon. P4 has a very small l1 cache, so unrolling will not give performance benefits here.
  202.   if ((env->GetCPUFlags() & CPUF_3DNOW_EXT)) {
  203.     unroll_fetch = true;
  204.   }
  205.   // We forcibly does not unroll fetch, if image width is more than 512
  206.   if (vi_src_width > 512) {
  207.     unroll_fetch = false;
  208.   }
  209.  
  210.   if (!(vi_src_width && vi_dst_width && vi_height)) { // Skip
  211.     x86.ret();
  212.     return DynamicAssembledCode(x86, env, "ResizeH: ISSE code could not be compiled.");
  213.   }
  214.  
  215.   int* array = (gen_plane == PLANAR_Y) ? pattern_luma : pattern_chroma;
  216.   int fir_filter_size = array[0];
  217.   int filter_offset=fir_filter_size*8+8;  // This is the length from one pixel pair to another
  218.   int* cur_luma = array+2;
  219.  
  220.   int six_loops = (vi_dst_width-2)/6;  // How many loops can we do safely, with 6 pixels.
  221.  
  222.   // Store registers
  223.   x86.push(eax);
  224.   x86.push(ebx);
  225.   x86.push(ecx);
  226.   x86.push(edx);
  227.   x86.push(esi);
  228.   x86.push(edi);
  229.   x86.push(ebp);
  230.  
  231.   // Initialize registers.
  232.   x86.mov(eax,(int)&FPround);
  233.   x86.pxor(mm6,mm6);  // Cleared mmx register - Not touched!
  234.   if (sse2)
  235.     x86.pxor(xmm6,xmm6);
  236.  
  237.   x86.movq(mm7, qword_ptr[eax]);  // Rounder for final division. Not touched!
  238.  
  239.   x86.mov(dword_ptr [&gen_h],vi_height);  // This is our y counter.
  240.  
  241.   x86.align(16);
  242.   x86.label("yloop");
  243.  
  244.   x86.mov(esi, dword_ptr[&gen_srcp]);
  245.   if (isse | sse2)
  246.     x86.prefetchnta(dword_ptr [esi]);  //Prefetch current cache line
  247.  
  248.   x86.mov(eax,dword_ptr [&gen_dstp]);
  249.   x86.mov(edi, dword_ptr[&tempY]);
  250.   x86.mov(dword_ptr [&gen_temp_destp],eax);
  251.  
  252.  
  253.   // Unpack source bytes to words in tempY buffer
  254.  
  255.   if (sse2) {
  256.     int mod64_w = mod16_w / 4;
  257.     int mod64_r = mod16_w % 4;
  258.     if (!mod64_r && mod64_w) {
  259.       mod64_w -= 1;
  260.       mod64_r += 4;
  261.     }
  262.  
  263.     if (mod64_w) {
  264.       if (mod64_w > 1) {
  265.         x86.mov(        ebx, mod64_w);
  266.         x86.align(16);
  267.         x86.label("fetch_loopback");
  268.       }
  269.       x86.prefetchnta(  dword_ptr [esi+64]);         //Prefetch one cache line ahead for single use
  270.       if (source_aligned) {                          // Load source
  271.         if (sse4) {
  272.           x86.movntdqa( xmm0, xmmword_ptr[esi]);     // fetch aligned dq word for single use
  273.           x86.movntdqa( xmm1, xmmword_ptr[esi+16]);
  274.           x86.movntdqa( xmm2, xmmword_ptr[esi+32]);
  275.           x86.movntdqa( xmm3, xmmword_ptr[esi+48]);
  276.         } else {
  277.           x86.movdqa(   xmm0, xmmword_ptr[esi]);     // fetch aligned dq word
  278.           x86.movdqa(   xmm1, xmmword_ptr[esi+16]);
  279.           x86.movdqa(   xmm2, xmmword_ptr[esi+32]);
  280.           x86.movdqa(   xmm3, xmmword_ptr[esi+48]);
  281.         }
  282.       } else {
  283.         if (sse3) {
  284.           x86.lddqu(    xmm0, xmmword_ptr[esi]);     // fast fetch unaligned dq word
  285.           x86.lddqu(    xmm1, xmmword_ptr[esi+16]);
  286.           x86.lddqu(    xmm2, xmmword_ptr[esi+32]);
  287.           x86.lddqu(    xmm3, xmmword_ptr[esi+48]);
  288.         } else {
  289.           x86.movdqu(   xmm0, xmmword_ptr[esi]);     // fetch unaligned dq word
  290.           x86.movdqu(   xmm1, xmmword_ptr[esi+16]);
  291.           x86.movdqu(   xmm2, xmmword_ptr[esi+32]);
  292.           x86.movdqu(   xmm3, xmmword_ptr[esi+48]);
  293.         }
  294.       }                                              // Unpack bytes -> words
  295.       x86.punpckhbw(    xmm4, xmm0);                 // xmm4 can contain junk, as this is cleared below.
  296.       x86.punpckhbw(    xmm5, xmm1);
  297.       x86.punpcklbw(    xmm0, xmm6);
  298.       x86.punpcklbw(    xmm1, xmm6);
  299.       x86.add(          esi, 64);
  300.       x86.psrlw(        xmm4, 8);                    // This will also clear out the junk in
  301.       x86.add(          edi, 128);                   // xmm4 that was there before the unpack
  302.       x86.psrlw(        xmm5, 8);
  303.       x86.movdqa(       xmmword_ptr[edi-128], xmm0);
  304.       x86.movdqa(       xmmword_ptr[edi-112], xmm4);
  305.       x86.movdqa(       xmmword_ptr[edi- 96], xmm1);
  306.       x86.movdqa(       xmmword_ptr[edi- 80], xmm5);
  307.  
  308.       x86.punpckhbw(    xmm4, xmm2);
  309.       x86.punpckhbw(    xmm5, xmm3);
  310.       x86.punpcklbw(    xmm2, xmm6);
  311.       x86.punpcklbw(    xmm3, xmm6);
  312.       x86.psrlw(        xmm4, 8);
  313.       if (mod64_w > 1)
  314.         x86.dec(        ebx);
  315.  
  316.       x86.psrlw(        xmm5, 8);
  317.       x86.movdqa(       xmmword_ptr[edi- 64], xmm2);
  318.       x86.movdqa(       xmmword_ptr[edi- 48], xmm4);
  319.       x86.movdqa(       xmmword_ptr[edi- 32], xmm3);
  320.       x86.movdqa(       xmmword_ptr[edi- 16], xmm5);
  321.       if (mod64_w > 1)
  322.         x86.jnz(        "fetch_loopback");
  323.     }
  324.  
  325.     if (source_aligned) {                            // Do the remainder
  326.       if (sse4) {
  327.         if (mod64_r > 0) x86.movntdqa( xmm0, xmmword_ptr[esi]);     // 16 pixels
  328.         if (mod64_r > 1) x86.movntdqa( xmm1, xmmword_ptr[esi+16]);  // 32 pixels
  329.         if (mod64_r > 2) x86.movntdqa( xmm2, xmmword_ptr[esi+32]);  // 48 pixels
  330.         if (mod64_r > 3) x86.movntdqa( xmm3, xmmword_ptr[esi+48]);  // 64 pixels
  331.       } else {
  332.         if (mod64_r > 0) x86.movdqa(   xmm0, xmmword_ptr[esi]);
  333.         if (mod64_r > 1) x86.movdqa(   xmm1, xmmword_ptr[esi+16]);
  334.         if (mod64_r > 2) x86.movdqa(   xmm2, xmmword_ptr[esi+32]);
  335.         if (mod64_r > 3) x86.movdqa(   xmm3, xmmword_ptr[esi+48]);
  336.       }
  337.     } else {
  338.       if (sse3) {
  339.         if (mod64_r > 0) x86.lddqu(    xmm0, xmmword_ptr[esi]);
  340.         if (mod64_r > 1) x86.lddqu(    xmm1, xmmword_ptr[esi+16]);
  341.         if (mod64_r > 2) x86.lddqu(    xmm2, xmmword_ptr[esi+32]);
  342.         if (mod64_r > 3) x86.lddqu(    xmm3, xmmword_ptr[esi+48]);
  343.       } else {
  344.         if (mod64_r > 0) x86.movdqu(   xmm0, xmmword_ptr[esi]);
  345.         if (mod64_r > 1) x86.movdqu(   xmm1, xmmword_ptr[esi+16]);
  346.         if (mod64_r > 2) x86.movdqu(   xmm2, xmmword_ptr[esi+32]);
  347.         if (mod64_r > 3) x86.movdqu(   xmm3, xmmword_ptr[esi+48]);
  348.       }
  349.     }
  350.     if (mod64_r > 0) x86.punpckhbw(    xmm4, xmm0);
  351.     if (mod64_r > 1) x86.punpckhbw(    xmm5, xmm1);
  352.     if (mod64_r > 0) x86.punpcklbw(    xmm0, xmm6);
  353.     if (mod64_r > 1) x86.punpcklbw(    xmm1, xmm6);
  354.     if (mod64_r > 0) x86.psrlw(        xmm4, 8);
  355.     if (mod64_r > 1) x86.psrlw(        xmm5, 8);
  356.     if (mod64_r > 0) x86.movdqa(       xmmword_ptr[edi+  0], xmm0);
  357.     if (mod64_r > 0) x86.movdqa(       xmmword_ptr[edi+ 16], xmm4);
  358.     if (mod64_r > 1) x86.movdqa(       xmmword_ptr[edi+ 32], xmm1);
  359.     if (mod64_r > 1) x86.movdqa(       xmmword_ptr[edi+ 48], xmm5);
  360.  
  361.     if (mod64_r > 2) x86.punpckhbw(    xmm4, xmm2);
  362.     if (mod64_r > 3) x86.punpckhbw(    xmm5, xmm3);
  363.     if (mod64_r > 2) x86.punpcklbw(    xmm2, xmm6);
  364.     if (mod64_r > 3) x86.punpcklbw(    xmm3, xmm6);
  365.     if (mod64_r > 2) x86.psrlw(        xmm4, 8);
  366.     if (mod64_r > 3) x86.psrlw(        xmm5, 8);
  367.     if (mod64_r > 2) x86.movdqa(       xmmword_ptr[edi+ 64], xmm2);
  368.     if (mod64_r > 2) x86.movdqa(       xmmword_ptr[edi+ 80], xmm4);
  369.     if (mod64_r > 3) x86.movdqa(       xmmword_ptr[edi+ 96], xmm3);
  370.     if (mod64_r > 3) x86.movdqa(       xmmword_ptr[edi+112], xmm5);
  371.  
  372.     if (mod64_r > 0) x86.add(          esi, mod64_r*16);
  373.     if (mod64_r > 0) x86.add(          edi, mod64_r*32);
  374.   } else {
  375.     for (int i=0;i<mod16_w;i++) {
  376.       if ((!(i%prefetchevery)) && ((prefetchevery+i)*16 < vi_src_width) && isse && unroll_fetch) {
  377.          //Prefetch only once per cache line
  378.         x86.prefetchnta(dword_ptr [esi+(prefetchevery*16)]);
  379.       }
  380.       if (!unroll_fetch) {  // Should we create a loop instead of unrolling?
  381.         i = mod16_w;  // Jump out of loop
  382.         x86.mov(ebx, mod16_w);
  383.         x86.align(16);
  384.         x86.label("fetch_loopback");
  385.       }
  386.       x86.movq(mm0, qword_ptr[esi]);        // Move pixels into mmx-registers
  387.        x86.movq(mm1, qword_ptr[esi+8]);
  388.       x86.movq(mm2,mm0);
  389.        x86.punpcklbw(mm0,mm6);     // Unpack bytes -> words
  390.       x86.movq(mm3,mm1);
  391.        x86.punpcklbw(mm1,mm6);
  392.       x86.add(esi,16);
  393.        x86.punpckhbw(mm2,mm6);
  394.       x86.add(edi,32);
  395.        x86.punpckhbw(mm3,mm6);
  396.       if (!unroll_fetch)   // Loop on if not unrolling
  397.         x86.dec(ebx);
  398.  
  399.       x86.movq(qword_ptr[edi-32],mm0);        // Store unpacked pixels in temporary space.
  400.       x86.movq(qword_ptr[edi+8-32],mm2);
  401.       x86.movq(qword_ptr[edi+16-32],mm1);
  402.       x86.movq(qword_ptr[edi+24-32],mm3);
  403.     }
  404.     if (!unroll_fetch)   // Loop on if not unrolling
  405.       x86.jnz("fetch_loopback");
  406.   }
  407.   switch (mod16_remain) {
  408.   case 3:
  409.     x86.movq(mm0, qword_ptr[esi]);        // Move 12 pixels into mmx-registers
  410.      x86.movd(mm1, dword_ptr[esi+8]);
  411.     x86.movq(mm2,mm0);
  412.      x86.punpcklbw(mm0,mm6);               // Unpack bytes -> words
  413.     x86.punpckhbw(mm2,mm6);
  414.      x86.punpcklbw(mm1,mm6);
  415.     x86.movq(qword_ptr[edi],mm0);         // Store 12 unpacked pixels in temporary space.
  416.      x86.movq(qword_ptr[edi+8],mm2);
  417.     x86.movq(qword_ptr[edi+16],mm1);
  418.     break;
  419.   case 2:
  420.     x86.movq(mm0, qword_ptr[esi]);        // Move 8 pixels into mmx-registers
  421.     x86.movq(mm2,mm0);
  422.      x86.punpcklbw(mm0,mm6);               // Unpack bytes -> words
  423.     x86.punpckhbw(mm2,mm6);
  424.      x86.movq(qword_ptr[edi],mm0);         // Store 8 unpacked pixels in temporary space.
  425.     x86.movq(qword_ptr[edi+8],mm2);
  426.     break;
  427.   case 1:
  428.     x86.movd(mm0,dword_ptr [esi]);        // Move 4 pixels into mmx-registers
  429.     x86.punpcklbw(mm0,mm6);               // Unpack bytes -> words
  430.     x86.movq(qword_ptr[edi],mm0);         // Store 4 unpacked pixels in temporary space.
  431.     break;
  432.   case 0:
  433.     break;
  434.   default:
  435.     env->ThrowError("Resize: FilteredResizeH::GenerateResizer illegal state %d.", mod16_remain);  // Opps!
  436.   }
  437.  
  438.   // Calculate destination pixels
  439.  
  440.   x86.mov(edi, (int)cur_luma);  // First there are offsets into the tempY planes, defining where the filter starts
  441.                                 // After that there is (filter_size) constants for multiplying.
  442.                                 // Next pixel pair is put after (filter_offset) bytes.
  443.  
  444.   if (six_loops) {       // Do we have at least 1 loops worth to do?
  445.     if (six_loops > 1) { // Do we have more than 1 loop to do?
  446.       x86.mov(dword_ptr [&gen_x],six_loops);
  447.       x86.align(16);
  448.       x86.label("xloop");
  449.     }
  450.     x86.mov(eax,dword_ptr [edi]);   // Move pointers of first pixel pair into registers
  451.     x86.mov(ebx,dword_ptr [edi+4]);
  452.     x86.mov(ecx,dword_ptr [edi+filter_offset]);     // Move pointers of next pixel pair into registers
  453.     x86.mov(edx,dword_ptr [edi+filter_offset+4]);
  454.     x86.movq(mm3,mm7);  // Start with rounder!
  455.     x86.mov(esi,dword_ptr [edi+(filter_offset*2)]);   // Move pointers of next pixel pair into registers
  456.     x86.movq(mm5,mm7);
  457.     x86.mov(ebp,dword_ptr [edi+(filter_offset*2)+4]);
  458.     x86.movq(mm4,mm7);
  459.     x86.add(edi,8); // cur_luma++
  460.  
  461.     for (int i=0;i<fir_filter_size;i++) {       // Unroll filter inner loop based on the filter size.
  462.         x86.movd(mm0, dword_ptr[eax+i*4]);
  463.          x86.movd(mm1, dword_ptr[ecx+i*4]);
  464.         x86.punpckldq(mm0, qword_ptr[ebx+i*4]);
  465.          x86.punpckldq(mm1, qword_ptr[edx+i*4]);
  466.         x86.pmaddwd(mm0, qword_ptr[edi+i*8]);
  467.          x86.movd(mm2, dword_ptr[esi+i*4]);
  468.         x86.pmaddwd(mm1,qword_ptr[edi+filter_offset+(i*8)]);
  469.          x86.punpckldq(mm2, qword_ptr[ebp+i*4]);
  470.         x86.paddd(mm3, mm0);
  471.          x86.pmaddwd(mm2, qword_ptr[edi+(filter_offset*2)+(i*8)]);
  472.         x86.paddd(mm4, mm1);
  473.          x86.paddd(mm5, mm2);
  474.     }
  475.     x86.psrad(mm3,14);
  476.      x86.mov(eax,dword_ptr[&gen_temp_destp]);
  477.     x86.psrad(mm4,14);
  478.      x86.add(dword_ptr [&gen_temp_destp],6);
  479.     x86.psrad(mm5,14);
  480.      x86.packssdw(mm3, mm4);       // [...3 ...2] [...1 ...0] => [.3 .2 .1 .0]
  481.     x86.packssdw(mm5, mm6);        // [...z ...z] [...5 ...4] => [.z .z .5 .4]
  482.      x86.add(edi,filter_offset*3-8);
  483.     x86.packuswb(mm3, mm5);        // [.z .z .5 .4] [.3 .2 .1 .0] => [zz543210]
  484.     if (six_loops > 1) {   // Do we have more than 1 loop to do?
  485.        x86.dec(dword_ptr [&gen_x]);
  486.       x86.movq(qword_ptr[eax],mm3);  // This was a potential 2 byte overwrite!
  487.        x86.jnz("xloop");
  488.     } else {
  489.       x86.movq(qword_ptr[eax],mm3);  // This was a potential 2 byte overwrite!
  490.     }
  491.   }
  492.  
  493.   // Process any remaining pixels
  494.  
  495. //      vi_dst_width;                              1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,10
  496. //      vi_dst_width-2                            -1,0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
  497. //      six_loops = (vi_dst_width-2)/6;            0,0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2
  498.   int remainx = vi_dst_width-(six_loops*6); //   1,2,3,4,5,6,7,2,3,4,5,6,7,2,3,4,5,6,7
  499.  
  500.   while (remainx>=4) {
  501.     x86.mov(eax,dword_ptr [edi]);
  502.     x86.mov(ebx,dword_ptr [edi+4]);
  503.     x86.movq(mm3,mm7);  // Used for pix 1+2
  504.     x86.mov(ecx,dword_ptr [edi+filter_offset]);
  505.     x86.movq(mm4,mm7);  // Used for pix 3+4
  506.     x86.mov(edx,dword_ptr [edi+filter_offset+4]);
  507.  
  508.     x86.add(edi,8); // cur_luma++
  509.     for (int i=0;i<fir_filter_size;i++) {
  510.       x86.movd(mm0, dword_ptr [eax+i*4]);
  511.        x86.movd(mm1, dword_ptr [ecx+i*4]);
  512.       x86.punpckldq(mm0, qword_ptr[ebx+i*4]);
  513.        x86.punpckldq(mm1, qword_ptr[edx+i*4]);
  514.       x86.pmaddwd(mm0, qword_ptr[edi+i*8]);
  515.        x86.pmaddwd(mm1, qword_ptr[edi+filter_offset+(i*8)]);
  516.       x86.paddd(mm3, mm0);
  517.        x86.paddd(mm4, mm1);
  518.     }
  519.     x86.psrad(mm3,14);
  520.     x86.psrad(mm4,14);
  521.     x86.mov(eax,dword_ptr[&gen_temp_destp]);
  522.     x86.packssdw(mm3, mm4);      // [...3 ...2] [...1 ...0] => [.3 .2 .1 .0]
  523.     x86.packuswb(mm3, mm6);      // [.. .. .. ..] [.3 .2 .1 .0] => [....3210]
  524.  
  525.     x86.movd(dword_ptr[eax],mm3);
  526.     remainx -= 4;
  527.     if (remainx) {
  528.       x86.add(dword_ptr [&gen_temp_destp],4);
  529.       x86.add(edi,filter_offset*2-8);
  530.     }
  531.   }
  532.   if (remainx==3) {
  533.     x86.mov(eax,dword_ptr [edi]);
  534.     x86.movq(mm3,mm7);  // Used for pix 1+2
  535.     x86.mov(ebx,dword_ptr [edi+4]);
  536.     x86.movq(mm4,mm7);  // Used for pix 3
  537.     x86.mov(ecx,dword_ptr [edi+filter_offset]);
  538.  
  539.     x86.add(edi,8); // cur_luma++
  540.     for (int i=0;i<fir_filter_size;i++) {
  541.       x86.movd(mm0, dword_ptr [eax+i*4]);
  542.        x86.movd(mm1, dword_ptr [ecx+i*4]);
  543.       x86.punpckldq(mm0, qword_ptr[ebx+i*4]);
  544.        x86.pmaddwd(mm1, qword_ptr[edi+filter_offset+(i*8)]);
  545.       x86.pmaddwd(mm0, qword_ptr[edi+i*8]);
  546.        x86.paddd(mm4, mm1);
  547.       x86.paddd(mm3, mm0);
  548.     }
  549.      x86.psrad(mm4,14);
  550.     x86.psrad(mm3,14);
  551.      x86.mov(eax,dword_ptr[&gen_temp_destp]);
  552.     x86.packssdw(mm3, mm4);      // [...z ...2] [...1 ...0] => [.z .2 .1 .0]
  553.      x86.movd(mm0,dword_ptr[eax]);
  554.     x86.packuswb(mm3, mm6);      // [.. .. .. ..] [.z .2 .1 .0] => [....z210]
  555.      x86.pand(mm0,qword_ptr[(int)&Mask3_pix_inv]);
  556.     x86.por(mm3,mm0);
  557.    
  558.     x86.movd(dword_ptr[eax],mm3);
  559.     remainx = 0;
  560.   }
  561.   if (remainx==2) {
  562.     x86.mov(eax,dword_ptr [edi]);
  563.     x86.movq(mm3,mm7);  // Used for pix 1+2
  564.     x86.mov(ebx,dword_ptr [edi+4]);
  565.  
  566.     x86.add(edi,8); // cur_luma++
  567.     for (int i=0;i<fir_filter_size;i+=2) {
  568.       const int j = i+1;
  569.       if (j < fir_filter_size) {
  570.         x86.movd(mm0, dword_ptr [eax+i*4]);
  571.          x86.movd(mm1, dword_ptr [eax+j*4]);
  572.         x86.punpckldq(mm0, qword_ptr[ebx+i*4]);
  573.          x86.punpckldq(mm1, qword_ptr[ebx+j*4]);
  574.         x86.pmaddwd(mm0, qword_ptr[edi+i*8]);
  575.          x86.pmaddwd(mm1, qword_ptr[edi+j*8]);
  576.         x86.paddd(mm3, mm0);
  577.         x86.paddd(mm3, mm1);
  578.       } else {
  579.         x86.movd(mm0, dword_ptr [eax+i*4]);
  580.         x86.punpckldq(mm0, qword_ptr[ebx+i*4]);
  581.         x86.pmaddwd(mm0, qword_ptr[edi+i*8]);
  582.         x86.paddd(mm3, mm0);
  583.       }
  584.     }
  585.      x86.mov(eax,dword_ptr[&gen_temp_destp]);
  586.     x86.psrad(mm3,14);
  587.      x86.movd(mm0,dword_ptr[eax]);
  588.     x86.packssdw(mm3, mm6);      // [...z ...z] [...1 ...0] => [.z .z .1 .0]
  589.      x86.pand(mm0,qword_ptr[(int)&Mask2_pix_inv]);
  590.     x86.packuswb(mm3, mm6);      // [.z .z .z .z] [.z .z .1 .0] => [zzzzzz10]
  591.      x86.por(mm3,mm0);
  592.      x86.movd(dword_ptr[eax],mm3);
  593.     remainx = 0;
  594.   }
  595.   if (remainx==1) {
  596.     x86.mov(eax,dword_ptr [edi]);
  597.     x86.movq(mm3,mm7);  // Used for pix 1
  598.  
  599.     x86.add(edi,8); // cur_luma++
  600.     for (int i=0;i<fir_filter_size;i+=2) {
  601.       const int j = i+1;
  602.       if (j < fir_filter_size) {
  603.         x86.movd(mm0, dword_ptr [eax+i*4]);
  604.          x86.movd(mm1, dword_ptr [eax+j*4]);
  605.         x86.pmaddwd(mm0, qword_ptr[edi+i*8]);
  606.          x86.pmaddwd(mm1, qword_ptr[edi+j*8]);
  607.         x86.paddd(mm3, mm0);
  608.         x86.paddd(mm3, mm1);
  609.       } else {
  610.         x86.movd(mm0, dword_ptr [eax+i*4]);
  611.         x86.pmaddwd(mm0, qword_ptr[edi+i*8]);
  612.         x86.paddd(mm3, mm0);
  613.       }
  614.     }
  615.      x86.mov(eax,dword_ptr[&gen_temp_destp]);
  616.     x86.psrad(mm3,14);
  617.      x86.movd(mm0,dword_ptr[eax]);
  618.     x86.pand(mm3,qword_ptr[(int)&Mask2_pix]);
  619.      x86.pand(mm0,qword_ptr[(int)&Mask1_pix_inv]);
  620.     x86.packuswb(mm3, mm6);      // [.z .z .z .z] [.z .z .Z .0] => [zzzzzzZ0]
  621.     x86.por(mm3,mm0);
  622.     x86.movd(dword_ptr[eax],mm3);
  623.     remainx = 0;
  624.   }
  625.  
  626.   // End remaining pixels
  627.  
  628.   x86.mov(eax,dword_ptr [&gen_src_pitch]);
  629.   x86.mov(ebx,dword_ptr [&gen_dst_pitch]);
  630.   x86.add(dword_ptr [&gen_srcp], eax);
  631.   x86.add(dword_ptr [&gen_dstp], ebx);
  632.  
  633.   x86.dec(dword_ptr [&gen_h]);
  634.   x86.jnz("yloop");
  635.   // No more mmx for now
  636.   x86.emms();
  637.   // Restore registers
  638.   x86.pop(ebp);
  639.   x86.pop(edi);
  640.   x86.pop(esi);
  641.   x86.pop(edx);
  642.   x86.pop(ecx);
  643.   x86.pop(ebx);
  644.   x86.pop(eax);
  645.   x86.ret();
  646.  
  647.   return DynamicAssembledCode(x86, env, "ResizeH: ISSE code could not be compiled.");
  648. }
  649.  
  650.  
  651.  
  652. PVideoFrame __stdcall FilteredResizeH::GetFrame(int n, IScriptEnvironment* env)
  653. {
  654.   PVideoFrame src = child->GetFrame(n, env);
  655.   PVideoFrame dst = env->NewVideoFrame(vi);
  656.   const BYTE* srcp = src->GetReadPtr();
  657.   BYTE* dstp = dst->GetWritePtr();
  658.   int src_pitch = src->GetPitch();
  659.   int dst_pitch = dst->GetPitch();
  660.   if (vi.IsPlanar()) {
  661.     int plane = 0;
  662.     gen_src_pitch = src_pitch;
  663.     gen_dst_pitch = dst_pitch;
  664.     gen_srcp = (BYTE*)srcp;
  665.     gen_dstp = dstp;
  666.     if (((int)gen_srcp & 15) || (gen_src_pitch & 15) || !assemblerY_aligned)
  667.       assemblerY.Call();
  668.     else
  669.       assemblerY_aligned.Call();
  670.  
  671.     if (src->GetRowSize(PLANAR_U)) {  // Y8 is finished here
  672.       gen_src_pitch = src->GetPitch(PLANAR_U);
  673.       gen_dst_pitch = dst->GetPitch(PLANAR_U);
  674.  
  675.       gen_srcp = (BYTE*)src->GetReadPtr(PLANAR_U);
  676.       gen_dstp = dst->GetWritePtr(PLANAR_U);
  677.       if (((int)gen_srcp & 15) || (gen_src_pitch & 15) || !assemblerUV_aligned)
  678.         assemblerUV.Call();
  679.       else
  680.         assemblerUV_aligned.Call();
  681.  
  682.       gen_srcp = (BYTE*)src->GetReadPtr(PLANAR_V);
  683.       gen_dstp = dst->GetWritePtr(PLANAR_V);
  684.       if (((int)gen_srcp & 15) || (gen_src_pitch & 15) || !assemblerUV_aligned)
  685.         assemblerUV.Call();
  686.       else
  687.         assemblerUV_aligned.Call();
  688.     }
  689.     return dst;
  690.   } else
  691.   if (vi.IsYUY2())
  692.   {
  693.     int fir_filter_size_luma = pattern_luma[0];
  694.     int fir_filter_size_chroma = pattern_chroma[0];
  695.     static const __int64 x0000000000FF00FF = 0x0000000000FF00FF;
  696.     static const __int64 xFFFF0000FFFF0000 = 0xFFFF0000FFFF0000;
  697.     static const __int64 FPround =           0x0000200000002000;  // 16384/2
  698.  
  699.     __asm {
  700.       pxor        mm0, mm0
  701.       movq        mm7, x0000000000FF00FF
  702.       movq        mm6, FPround
  703.       movq        mm5, xFFFF0000FFFF0000
  704.     }
  705.     if (env->GetCPUFlags() & CPUF_INTEGER_SSE) {
  706.      for (int y=0; y<vi.height; ++y)
  707.       {
  708.         int* cur_luma = pattern_luma+2;
  709.         int* cur_chroma = pattern_chroma+2;
  710.         int x = vi.width / 2;
  711.  
  712.         __asm {
  713.             push ebx    // stupid compiler forgets to save ebx!!
  714.         mov         edi, this
  715.         mov         ecx, [edi].original_width
  716.         mov         edx, [edi].tempY
  717.         mov         ebx, [edi].tempUV
  718.         mov         esi, srcp
  719.         mov         eax, -1
  720.       // deinterleave current line
  721.         align 16
  722.       i_deintloop:
  723.         prefetchnta [esi+256]
  724.         movd        mm1, [esi]          ;mm'1 = 00 00 VY UY
  725.        inc         eax
  726.        movq        mm2, mm1
  727.        punpcklbw   mm2, mm0            ;mm2 = 0V 0Y 0U 0Y
  728.        pand        mm1, mm7            ;mm1 = 00 00 0Y 0Y
  729.        movd        [edx+eax*4], mm1
  730.        psrld       mm2, 16             ;mm2 = 00 0V 00 0U
  731.        add         esi, 4
  732.        movq        [ebx+eax*8], mm2
  733.        sub         ecx, 2
  734.        jnz         i_deintloop
  735.      // use this as source from now on
  736.        mov         eax, cur_luma
  737.        mov         ebx, cur_chroma
  738.        mov         edx, dstp
  739.        align 16
  740.      i_xloopYUV:
  741.        mov         esi, [eax]          ;esi=&tempY[ofs0]
  742.        movq        mm1, mm0
  743.        mov         edi, [eax+4]        ;edi=&tempY[ofs1]
  744.        movq        mm3, mm0
  745.        mov         ecx, fir_filter_size_luma
  746.        add         eax, 8              ;cur_luma++
  747.        align 16
  748.      i_aloopY:
  749.        // Identifiers:
  750.        // Ya, Yb: Y values in srcp[ofs0]
  751.        // Ym, Yn: Y values in srcp[ofs1]
  752.        movd        mm2, [esi]          ;mm2 =  0| 0|Yb|Ya
  753.        add         esi, 4
  754.        punpckldq   mm2, [edi]          ;mm2 = Yn|Ym|Yb|Ya
  755.                                        ;[eax] = COn|COm|COb|COa
  756.        add         edi, 4
  757.        pmaddwd     mm2, [eax]          ;mm2 = Y1|Y0 (DWORDs)
  758.        add         eax, 8              ;cur_luma++
  759.        dec         ecx
  760.        paddd       mm1, mm2            ;accumulate
  761.        jz         out_i_aloopY
  762. //unroll1
  763.        movd        mm2, [esi]          ;mm2 =  0| 0|Yb|Ya
  764.        add         esi, 4
  765.        punpckldq   mm2, [edi]          ;mm2 = Yn|Ym|Yb|Ya
  766.                                        ;[eax] = COn|COm|COb|COa
  767.        add         edi, 4
  768.        pmaddwd     mm2, [eax]          ;mm2 = Y1|Y0 (DWORDs)
  769.        add         eax, 8              ;cur_luma++
  770.        dec         ecx
  771.        paddd       mm1, mm2            ;accumulate
  772.        jz         out_i_aloopY
  773. //unroll2
  774.        movd        mm2, [esi]          ;mm2 =  0| 0|Yb|Ya
  775.        add         esi, 4
  776.        punpckldq   mm2, [edi]          ;mm2 = Yn|Ym|Yb|Ya
  777.                                        ;[eax] = COn|COm|COb|COa
  778.        add         edi, 4
  779.        pmaddwd     mm2, [eax]          ;mm2 = Y1|Y0 (DWORDs)
  780.        add         eax, 8              ;cur_luma++
  781.        dec         ecx
  782.        paddd       mm1, mm2            ;accumulate
  783.        jz         out_i_aloopY
  784. //unroll3
  785.        movd        mm2, [esi]          ;mm2 =  0| 0|Yb|Ya
  786.        add         esi, 4
  787.        punpckldq   mm2, [edi]          ;mm2 = Yn|Ym|Yb|Ya
  788.                                        ;[eax] = COn|COm|COb|COa
  789.        add         edi, 4
  790.        pmaddwd     mm2, [eax]          ;mm2 = Y1|Y0 (DWORDs)
  791.        add         eax, 8              ;cur_luma++
  792.        dec         ecx
  793.        paddd       mm1, mm2            ;accumulate
  794.        jz         out_i_aloopY
  795. //unroll4
  796.        movd        mm2, [esi]          ;mm2 =  0| 0|Yb|Ya
  797.        add         esi, 4
  798.        punpckldq   mm2, [edi]          ;mm2 = Yn|Ym|Yb|Ya
  799.                                        ;[eax] = COn|COm|COb|COa
  800.        add         edi, 4
  801.        pmaddwd     mm2, [eax]          ;mm2 = Y1|Y0 (DWORDs)
  802.        add         eax, 8              ;cur_luma++
  803.        dec         ecx
  804.        paddd       mm1, mm2            ;accumulate
  805.        jz         out_i_aloopY
  806. //unroll5
  807.        movd        mm2, [esi]          ;mm2 =  0| 0|Yb|Ya
  808.        add         esi, 4
  809.        punpckldq   mm2, [edi]          ;mm2 = Yn|Ym|Yb|Ya
  810.                                        ;[eax] = COn|COm|COb|COa
  811.        add         edi, 4
  812.        pmaddwd     mm2, [eax]          ;mm2 = Y1|Y0 (DWORDs)
  813.        add         eax, 8              ;cur_luma++
  814.        dec         ecx
  815.        paddd       mm1, mm2            ;accumulate
  816.        jz         out_i_aloopY
  817. //unroll6
  818.        movd        mm2, [esi]          ;mm2 =  0| 0|Yb|Ya
  819.        add         esi, 4
  820.        punpckldq   mm2, [edi]          ;mm2 = Yn|Ym|Yb|Ya
  821.                                        ;[eax] = COn|COm|COb|COa
  822.        add         edi, 4
  823.        pmaddwd     mm2, [eax]          ;mm2 = Y1|Y0 (DWORDs)
  824.        add         eax, 8              ;cur_luma++
  825.        dec         ecx
  826.        paddd       mm1, mm2            ;accumulate
  827.        jz         out_i_aloopY
  828. //unroll7
  829.        movd        mm2, [esi]          ;mm2 =  0| 0|Yb|Ya
  830.        add         esi, 4
  831.        punpckldq   mm2, [edi]          ;mm2 = Yn|Ym|Yb|Ya
  832.                                        ;[eax] = COn|COm|COb|COa
  833.        add         edi, 4
  834.        pmaddwd     mm2, [eax]          ;mm2 = Y1|Y0 (DWORDs)
  835.        add         eax, 8              ;cur_luma++
  836.        dec         ecx
  837.        paddd       mm1, mm2            ;accumulate
  838.        jnz         i_aloopY
  839.        align 16
  840. out_i_aloopY:
  841.        mov         esi, [ebx]          ;esi=&tempUV[ofs]
  842.        add         ebx, 8              ;cur_chroma++
  843.        mov         ecx, fir_filter_size_chroma
  844.        align 16
  845.      i_aloopUV:
  846.        movq        mm2, [esi]          ;mm2 = 0|V|0|U
  847.                                        ;[ebx] = 0|COv|0|COu
  848.        add         esi, 8
  849.        pmaddwd     mm2, [ebx]          ;mm2 = V|U (DWORDs)
  850.        add         ebx, 8              ;cur_chroma++
  851.        dec         ecx
  852.        paddd       mm3, mm2            ;accumulate
  853.        jz         out_i_aloopUV
  854. //unroll1
  855.        movq        mm2, [esi]          ;mm2 = 0|V|0|U
  856.                                        ;[ebx] = 0|COv|0|COu
  857.        add         esi, 8
  858.        pmaddwd     mm2, [ebx]          ;mm2 = V|U (DWORDs)
  859.        add         ebx, 8              ;cur_chroma++
  860.        dec         ecx
  861.        paddd       mm3, mm2            ;accumulate
  862.        jz         out_i_aloopUV
  863. //unroll2
  864.        movq        mm2, [esi]          ;mm2 = 0|V|0|U
  865.                                        ;[ebx] = 0|COv|0|COu
  866.        add         esi, 8
  867.        pmaddwd     mm2, [ebx]          ;mm2 = V|U (DWORDs)
  868.        add         ebx, 8              ;cur_chroma++
  869.        dec         ecx
  870.        paddd       mm3, mm2            ;accumulate
  871.        jz         out_i_aloopUV
  872. //unroll3
  873.        movq        mm2, [esi]          ;mm2 = 0|V|0|U
  874.                                        ;[ebx] = 0|COv|0|COu
  875.        add         esi, 8
  876.        pmaddwd     mm2, [ebx]          ;mm2 = V|U (DWORDs)
  877.        add         ebx, 8              ;cur_chroma++
  878.        dec         ecx
  879.        paddd       mm3, mm2            ;accumulate
  880.        jz         out_i_aloopUV
  881. //unroll4
  882.        movq        mm2, [esi]          ;mm2 = 0|V|0|U
  883.                                        ;[ebx] = 0|COv|0|COu
  884.        add         esi, 8
  885.        pmaddwd     mm2, [ebx]          ;mm2 = V|U (DWORDs)
  886.        add         ebx, 8              ;cur_chroma++
  887.        dec         ecx
  888.        paddd       mm3, mm2            ;accumulate
  889.        jz         out_i_aloopUV
  890. //unroll5
  891.        movq        mm2, [esi]          ;mm2 = 0|V|0|U
  892.                                        ;[ebx] = 0|COv|0|COu
  893.        add         esi, 8
  894.        pmaddwd     mm2, [ebx]          ;mm2 = V|U (DWORDs)
  895.        add         ebx, 8              ;cur_chroma++
  896.        dec         ecx
  897.        paddd       mm3, mm2            ;accumulate
  898.        jz         out_i_aloopUV
  899. //unroll6
  900.        movq        mm2, [esi]          ;mm2 = 0|V|0|U
  901.                                        ;[ebx] = 0|COv|0|COu
  902.        add         esi, 8
  903.        pmaddwd     mm2, [ebx]          ;mm2 = V|U (DWORDs)
  904.        add         ebx, 8              ;cur_chroma++
  905.        dec         ecx
  906.        paddd       mm3, mm2            ;accumulate
  907.        jz         out_i_aloopUV
  908. //unroll7
  909.        movq        mm2, [esi]          ;mm2 = 0|V|0|U
  910.                                        ;[ebx] = 0|COv|0|COu
  911.        add         esi, 8
  912.        pmaddwd     mm2, [ebx]          ;mm2 = V|U (DWORDs)
  913.        add         ebx, 8              ;cur_chroma++
  914.        dec         ecx
  915.        paddd       mm3, mm2            ;accumulate
  916.        jnz         i_aloopUV
  917.        align 16
  918. out_i_aloopUV:
  919.        paddd       mm3, mm6            ; V| V| U| U  (round)
  920.         paddd       mm1, mm6            ;Y1|Y1|Y0|Y0  (round)
  921.        pslld       mm3, 2              ; Shift up from 14 bits fraction to 16 bit fraction
  922.         pxor        mm4,mm4             ;Clear mm4 - utilize shifter stall
  923.        psrad       mm1, 14             ;mm1 = --y1|--y0
  924.        pmaxsw      mm1,mm4             ;Clamp at 0
  925.        pand        mm3, mm5            ;mm3 = v| 0|u| 0
  926.        por         mm3,mm1
  927.        packuswb    mm3, mm3            ;mm3 = ...|v|y1|u|y0
  928.        movd        [edx], mm3
  929.        add         edx, 4
  930.        dec         x
  931.        jnz         i_xloopYUV
  932.           pop ebx
  933.        }
  934.        srcp += src_pitch;
  935.        dstp += dst_pitch;
  936.      }
  937.    } else {  // MMX
  938.      for (int y=0; y<vi.height; ++y)
  939.      {
  940.        int* cur_luma = pattern_luma+2;
  941.        int* cur_chroma = pattern_chroma+2;
  942.        int x = vi.width / 2;
  943.  
  944.        __asm {
  945.         push ebx    // stupid compiler forgets to save ebx!!
  946.        mov         edi, this
  947.        mov         ecx, [edi].original_width
  948.        mov         edx, [edi].tempY
  949.        mov         ebx, [edi].tempUV
  950.        mov         esi, srcp
  951.        mov         eax, -1
  952.      // deinterleave current line
  953.        align 16
  954.      deintloop:
  955.        inc         eax
  956.        movd        mm1, [esi]          ;mm1 = 0000VYUY
  957.        movq        mm2, mm1
  958.        punpcklbw   mm2, mm0            ;mm2 = 0V0Y0U0Y
  959.         pand        mm1, mm7            ;mm1 = 00000Y0Y
  960.        movd        [edx+eax*4], mm1
  961.         psrld       mm2, 16             ;mm2 = 000V000U
  962.        add         esi, 4
  963.        movq        [ebx+eax*8], mm2
  964.        sub         ecx, 2
  965.        jnz         deintloop
  966.      // use this as source from now on
  967.        mov         eax, cur_luma
  968.        mov         ebx, cur_chroma
  969.        mov         edx, dstp
  970.        align 16
  971.      xloopYUV:
  972.        mov         esi, [eax]          ;esi=&tempY[ofs0]
  973.        movq        mm1, mm0
  974.        mov         edi, [eax+4]        ;edi=&tempY[ofs1]
  975.        movq        mm3, mm0
  976.        mov         ecx, fir_filter_size_luma
  977.        add         eax, 8              ;cur_luma++
  978.        align 16
  979.      aloopY:
  980.        // Identifiers:
  981.        // Ya, Yb: Y values in srcp[ofs0]
  982.        // Ym, Yn: Y values in srcp[ofs1]
  983.        movd        mm2, [esi]          ;mm2 =  0| 0|Yb|Ya
  984.        add         esi, 4
  985.        punpckldq   mm2, [edi]          ;mm2 = Yn|Ym|Yb|Ya
  986.                                        ;[eax] = COn|COm|COb|COa
  987.        add         edi, 4
  988.        pmaddwd     mm2, [eax]          ;mm2 = Y1|Y0 (DWORDs)
  989.        add         eax, 8              ;cur_luma++
  990.        dec         ecx
  991.        paddd       mm1, mm2            ;accumulate
  992.        jnz         aloopY
  993.  
  994.        mov         esi, [ebx]          ;esi=&tempUV[ofs]
  995.        add         ebx, 8              ;cur_chroma++
  996.        mov         ecx, fir_filter_size_chroma
  997.        align 16
  998.      aloopUV:
  999.        movq        mm2, [esi]          ;mm2 = 0|V|0|U
  1000.                                        ;[ebx] = 0|COv|0|COu
  1001.        add         esi, 8
  1002.        pmaddwd     mm2, [ebx]          ;mm2 = V|U (DWORDs)
  1003.        add         ebx, 8              ;cur_chroma++
  1004.        dec         ecx
  1005.        paddd       mm3, mm2            ;accumulate
  1006.        jnz         aloopUV
  1007.         paddd       mm1, mm6           ; Y1|Y1|Y0|Y0  (round)
  1008.        paddd       mm3, mm6            ; V| V| U| U  (round)
  1009.         psrad       mm1, 14            ; mm1 = 0|y1|0|y0
  1010.         pslld       mm3, 2             ; Shift up from 14 bits fraction to 16 bit fraction
  1011.        movq        mm4, mm1
  1012.         psrad       mm1, 31            ; sign extend right
  1013.        pand        mm3, mm5            ; mm3 = v| 0|u| 0
  1014.         pandn       mm1, mm4           ; clip luma at 0
  1015.         por         mm3, mm1
  1016.        add         edx, 4
  1017.         packuswb    mm3, mm3            ; mm3 = ...|v|y1|u|y0
  1018.        dec         x
  1019.        movd        [edx-4], mm3
  1020.        jnz         xloopYUV
  1021.             pop ebx
  1022.        }
  1023.        srcp += src_pitch;
  1024.        dstp += dst_pitch;
  1025.      }
  1026.    }
  1027.    __asm { emms }
  1028.  }
  1029.  else
  1030.  if (vi.IsRGB24())
  1031.  {
  1032.    // RGB24 is not recommended. 75% of all pixels are not aligned.
  1033.    int y = vi.height;
  1034.    int w = vi.width * 3;
  1035.    int fir_filter_size = pattern_luma[0];
  1036.    int* pattern_lumaP1 = pattern_luma+1 - fir_filter_size;
  1037.    static const __int64 xFF000000 = 0xFF000000;
  1038.    static const __int64 FPround   = 0x0000200000002000;  // 16384/2
  1039.    __asm {
  1040.       push        ebx
  1041.      mov         esi, srcp
  1042.      mov         edi, dstp
  1043.      pxor        mm2, mm2
  1044.      movq        mm4, xFF000000
  1045.      align 16
  1046.    yloop24:
  1047.      xor         ecx, ecx
  1048.      mov         edx, pattern_lumaP1       ;cur - fir_filter_size
  1049.      align 16
  1050.    xloop24:
  1051.      mov         eax, fir_filter_size
  1052.      movq        mm0, FPround              ;btotal, gtotal
  1053.      lea         edx, [edx+eax*4]          ;cur += fir_filter_size
  1054.      movq        mm1, mm0                  ;rtotal
  1055.      mov         ebx, [edx]
  1056.      add         edx, 4                    ;cur++
  1057.      lea         ebx, [ebx+ebx*2]          ;ebx = ofs = *cur * 3
  1058.      lea         edx, [edx+eax*4]          ;cur += fir_filter_size
  1059.      add         ebx, esi                  ;ebx = srcp + ofs*3
  1060.      lea         eax, [eax+eax*2]          ;eax = a = fir_filter_size*3
  1061.      align 16
  1062.    aloop24:
  1063.      sub         edx, 4                    ;cur--
  1064.      sub         eax, 3
  1065.      movd        mm5, [edx]                ;mm5 =    00|co (co = coefficient)
  1066.      movd        mm7, [ebx+eax]            ;mm7 = srcp[ofs+a] = 0|0|0|0|x|r|g|b
  1067.      packssdw    mm5, mm2
  1068.      punpcklbw   mm7, mm2                  ;mm7 = 0x|0r|0g|0b
  1069.      punpckldq   mm5, mm5                  ;mm5 =    co|co
  1070.      movq        mm6, mm7
  1071.      punpcklwd   mm7, mm2                  ;mm7 = 00|0g|00|0b
  1072.      punpckhwd   mm6, mm2                  ;mm6 = 00|0x|00|0r
  1073.      pmaddwd     mm7, mm5                  ;mm7 =  g*co|b*co
  1074.      pmaddwd     mm6, mm5                  ;mm6 =  x*co|r*co
  1075.      paddd       mm0, mm7
  1076.      paddd       mm1, mm6
  1077.      jnz         aloop24
  1078.  
  1079.      pslld       mm0, 2
  1080.      pslld       mm1, 2                    ;compensate the fact that FPScale = 16384
  1081.      packuswb    mm0, mm1                  ;mm0 = x|_|r|_|g|_|b|_
  1082.      psrlw       mm0, 8                    ;mm0 = 0|x|0|r|0|g|0|b
  1083.      packuswb    mm0, mm2                  ;mm0 = 0|0|0|0|x|r|g|b
  1084.      movd        mm3, [edi+ecx]            ;mm3 = 0|0|0|0|x|r|g|b (dst)
  1085.      pslld       mm0, 8                    ;mm0 = 0|0|0|0|r|g|b|0
  1086.      pand        mm3, mm4                  ;mm3 = 0|0|0|0|x|0|0|0 (dst)
  1087.      psrld       mm0, 8                    ;mm0 = 0|0|0|0|0|r|g|b
  1088.      add         ecx, 3
  1089.      por         mm3, mm0
  1090.      cmp         ecx, w
  1091.      movd        [edi+ecx-3], mm3
  1092.      jnz         xloop24
  1093.  
  1094.      add         esi, src_pitch
  1095.      add         edi, dst_pitch
  1096.      dec         y
  1097.      jnz         yloop24
  1098.      emms
  1099.       pop         ebx
  1100.    }
  1101.  }
  1102.  else
  1103.  {
  1104.    // RGB32
  1105.    int y = vi.height;
  1106.    int w = vi.width;
  1107.    int fir_filter_size = pattern_luma[0];
  1108.    int* pattern_lumaP1 = &pattern_luma[1] - fir_filter_size;
  1109.    static const int FPround = 0x00002000;  // 16384/2
  1110.  
  1111.    __asm {
  1112.       push        ebx
  1113.      mov         esi, srcp
  1114.      movd        mm3, FPround
  1115.      mov         edi, dstp
  1116.       punpckldq   mm3, mm3
  1117.      pxor        mm2, mm2
  1118.      align 16
  1119.    yloop32:
  1120.      xor         ecx, ecx
  1121.      mov         edx, pattern_lumaP1       ;cur - fir_filter_size
  1122.      align 16
  1123.    xloop32:
  1124.      mov         eax, fir_filter_size
  1125.      movq        mm0, mm3                  ;btotal, gtotal
  1126.      lea         edx, [edx+eax*4]          ;cur += fir_filter_size
  1127.      movq        mm1, mm3                  ;atotal, rtotal
  1128.      mov         ebx, [edx]
  1129.      add         edx, 4                    ;cur++
  1130.      shl         ebx, 2                    ;ebx = ofs = *cur * 4
  1131.      lea         edx, [edx+eax*4]          ;cur += fir_filter_size
  1132.      add         ebx, esi                  ;ebx = srcp + ofs*4
  1133.      align 16
  1134.    aloop32:
  1135.      sub         edx, 4                    ;cur--
  1136.      movd        mm7, [ebx+eax*4-4]        ;mm7 = srcp[ofs+a] = 0|0|0|0|a|r|g|b
  1137.      movd        mm5, [edx]                ;mm5 =    00|co (co = coefficient)
  1138.      punpcklbw   mm7, mm2                  ;mm7 = 0a|0r|0g|0b
  1139.      packssdw    mm5, mm2
  1140.      movq        mm6, mm7
  1141.      punpcklwd   mm7, mm2                  ;mm7 = 00|0g|00|0b
  1142.      punpckldq   mm5, mm5                  ;mm5 =    co|co
  1143.      punpckhwd   mm6, mm2                  ;mm6 = 00|0a|00|0r
  1144.      pmaddwd     mm7, mm5                  ;mm7 =  g*co|b*co
  1145.      dec         eax
  1146.      pmaddwd     mm6, mm5                  ;mm6 =  a*co|r*co
  1147.      paddd       mm0, mm7
  1148.      paddd       mm1, mm6
  1149.      jnz         aloop32
  1150.  
  1151.      pslld       mm0, 2
  1152.      pslld       mm1, 2                    ;compensate the fact that FPScale = 16384
  1153.      packuswb    mm0, mm1                  ;mm0 = a|_|r|_|g|_|b|_
  1154.      psrlw       mm0, 8                    ;mm0 = 0|a|0|r|0|g|0|b
  1155.      inc         ecx
  1156.      packuswb    mm0, mm2                  ;mm0 = 0|0|0|0|a|r|g|b
  1157.      cmp         ecx, w
  1158.      movd        [edi+ecx*4-4], mm0
  1159.      jnz         xloop32
  1160.  
  1161.      add         esi, src_pitch
  1162.      add         edi, dst_pitch
  1163.      dec         y
  1164.      jnz         yloop32
  1165.      emms
  1166.       pop         ebx
  1167.    }
  1168.  }
  1169.  return dst;
  1170. }
  1171.  
  1172.  
  1173. FilteredResizeH::~FilteredResizeH(void)
  1174. {
  1175.  if (pattern_luma) _aligned_free(pattern_luma);
  1176.  if (pattern_chroma) _aligned_free(pattern_chroma);
  1177.  if (tempY)
  1178.  {
  1179.    if (tempUV) _aligned_free(tempUV);
  1180.    if (tempY) _aligned_free(tempY);
  1181.  }
  1182.  assemblerY.Free();
  1183.  assemblerUV.Free();
  1184.  assemblerY_aligned.Free();
  1185.  assemblerUV_aligned.Free();
  1186. }
  1187.  
  1188.  
  1189.  
  1190. /***************************************
  1191. ***** Filtered Resize - Vertical ******
  1192. ***************************************/
  1193.  
  1194. FilteredResizeV::FilteredResizeV( PClip _child, double subrange_top, double subrange_height,
  1195.                                  int target_height, ResamplingFunction* func, IScriptEnvironment* env )
  1196.  : GenericVideoFilter(_child), resampling_pattern(0), resampling_patternUV(0),
  1197.    yOfs(0), yOfsUV(0), pitch_gY(-1), pitch_gUV(-1)
  1198. {
  1199.  if (target_height<=0)
  1200.    env->ThrowError("Resize: Height must be greater than 0.");
  1201.  
  1202.  if (vi.IsPlanar() && !vi.IsY8()) {
  1203.    const int mask = (1 << vi.GetPlaneHeightSubsampling(PLANAR_U)) - 1;
  1204.  
  1205.    if (target_height & mask)
  1206.      env->ThrowError("Resize: Planar destination height must be a multiple of %d.", mask+1);
  1207.  }
  1208.  
  1209.  if (vi.IsRGB())
  1210.    subrange_top = vi.height - subrange_top - subrange_height;
  1211.  
  1212.  resampling_pattern = func->GetResamplingPatternRGB(vi.height, subrange_top, subrange_height, target_height, env);
  1213.  
  1214.  if (vi.IsPlanar() && !vi.IsY8()) {
  1215.    const int shift = vi.GetPlaneHeightSubsampling(PLANAR_U);
  1216.    const int div   = 1 << shift;
  1217.  
  1218.    resampling_patternUV = func->GetResamplingPatternRGB(
  1219.                                          vi.height      >> shift,
  1220.                                          subrange_top    / div,
  1221.                                          subrange_height / div,
  1222.                                          target_height  >> shift,
  1223.                                          env);
  1224.  }
  1225.  
  1226.  vi.height = target_height;
  1227.  
  1228.  try {
  1229.    assemblerY         = GenerateResizer(PLANAR_Y, false, env);
  1230.    assemblerY_aligned = GenerateResizer(PLANAR_Y, true, env);
  1231.    if (vi.IsPlanar() && !vi.IsY8()) {
  1232.      assemblerUV         = GenerateResizer(PLANAR_U, false, env);
  1233.      assemblerUV_aligned = GenerateResizer(PLANAR_U, true, env);
  1234.    }
  1235.  }
  1236.  catch (SoftWire::Error err) {
  1237.     env->ThrowError("Resize: SoftWire exception : %s", err.getString());
  1238.  }
  1239. }
  1240.  
  1241.  
  1242. /*******************************
  1243. * Note on multithreading (Klaus Post, 2007):
  1244. * GetFrame is currently not re-entrant due to dynamic code variables.
  1245. * I have not been able to find a good solution for this
  1246. * (pushing a struct pointer to dynamic data on to the stack is not a solution IMO).
  1247. * We could guard the function, to avoid re-entrance.
  1248. ******************************/
  1249.  
  1250.  
  1251. PVideoFrame __stdcall FilteredResizeV::GetFrame(int n, IScriptEnvironment* env)
  1252. {
  1253.  PVideoFrame src = child->GetFrame(n, env);
  1254.  PVideoFrame dst = env->NewVideoFrame(vi);
  1255.  src_pitch = src->GetPitch();
  1256.  dst_pitch = dst->GetPitch();
  1257.  srcp = src->GetReadPtr();
  1258.  dstp = dst->GetWritePtr();
  1259.  y = vi.height;
  1260.  int plane = vi.IsPlanar() && (!vi.IsY8()) ? 4:1;
  1261.  
  1262.  if (pitch_gUV != src->GetPitch(PLANAR_U)) {  // Pitch is not the same as last frame
  1263.    int shUV = src->GetHeight(PLANAR_U);
  1264.    pitch_gUV = src->GetPitch(PLANAR_U);
  1265.  
  1266.    if (!yOfsUV)
  1267.      yOfsUV = new int[shUV];
  1268.  
  1269.    for (int i = 0; i < shUV; i++)
  1270.      yOfsUV[i] = pitch_gUV * i;
  1271.  }
  1272.  
  1273.  if (pitch_gY != src->GetPitch(PLANAR_Y))  { // Pitch is not the same as last frame
  1274.    int sh = src->GetHeight();
  1275.    pitch_gY = src->GetPitch(PLANAR_Y);
  1276.  
  1277.    if (!yOfs)
  1278.      yOfs = new int[sh];
  1279.  
  1280.    for (int i = 0; i < sh; i++)
  1281.      yOfs[i] = pitch_gY * i;
  1282.  }
  1283.  
  1284.  yOfs2 = this->yOfs;
  1285.  
  1286.  while (plane-->0){
  1287.    switch (plane) {
  1288.      case 2:  // take V plane
  1289.        src_pitch = src->GetPitch(PLANAR_V);
  1290.        dst_pitch = dst->GetPitch(PLANAR_V);
  1291.        dstp = dst->GetWritePtr(PLANAR_V);
  1292.        srcp = src->GetReadPtr(PLANAR_V);
  1293.        y = dst->GetHeight(PLANAR_V);
  1294.        yOfs2 = this->yOfsUV;
  1295.        if (((int)srcp & 15) || (src_pitch & 15) || !assemblerUV_aligned)
  1296.          assemblerUV.Call();
  1297.        else
  1298.          assemblerUV_aligned.Call();
  1299.        break;
  1300.      case 1: // U Plane
  1301.        dstp = dst->GetWritePtr(PLANAR_U);
  1302.        srcp = src->GetReadPtr(PLANAR_U);
  1303.        y = dst->GetHeight(PLANAR_U);
  1304.        src_pitch = src->GetPitch(PLANAR_U);
  1305.        dst_pitch = dst->GetPitch(PLANAR_U);
  1306.        yOfs2 = this->yOfsUV;
  1307.        plane--; // skip case 0
  1308.        if (((int)srcp & 15) || (src_pitch & 15) || !assemblerUV_aligned)
  1309.          assemblerUV.Call();
  1310.        else
  1311.          assemblerUV_aligned.Call();
  1312.        break;
  1313.      case 3: // Y plane for planar
  1314.      case 0: // Default for interleaved
  1315.        if (((int)srcp & 15) || (src_pitch & 15) || !assemblerY_aligned)
  1316.          assemblerY.Call();
  1317.        else
  1318.          assemblerY_aligned.Call();
  1319.        break;
  1320.    }
  1321.  } // end while
  1322.  return dst;
  1323. }
  1324.  
  1325.  
  1326. FilteredResizeV::~FilteredResizeV(void)
  1327. {
  1328.  if (resampling_pattern) { _aligned_free(resampling_pattern); resampling_pattern = 0; }
  1329.  if (resampling_patternUV) { _aligned_free(resampling_patternUV); resampling_patternUV = 0; }
  1330.  if (yOfs) { delete[] yOfs; yOfs = 0; }
  1331.  if (yOfsUV) { delete[] yOfsUV; yOfsUV = 0; }
  1332.  assemblerY.Free();
  1333.  assemblerUV.Free();
  1334.  assemblerY_aligned.Free();
  1335.  assemblerUV_aligned.Free();
  1336. }
  1337.  
  1338.  
  1339.  
  1340. /***********************************
  1341. * Dynamically Assembled Resampler
  1342. *
  1343. * (c) 2007, Klaus Post
  1344. * (c) 2009, Ian Brabham
  1345. *
  1346. * Dynamic version of the Vertical resizer
  1347. *
  1348. * The Algorithm is the same, except this
  1349. *  one is able to process 16 pixels in parallel in SSE2+, 8 pixels in MMX.
  1350. * The inner loop filter is unrolled based on the
  1351. *  exact filter size.
  1352. * SSSE3 version is approximately twice as fast as original MMX,
  1353. * SSE2 version is approximately 60% faster than new MMX,
  1354. * New mmx version is approximately 55% faster than original MMX,
  1355. * SSSE3 PSNR is more than 67dB to MMX version using 4 taps. i.e <1 bit
  1356. * SSE2 is bit identical with MMX.
  1357. * align parameter indicates if source plane and pitch is 16 byte aligned for sse2+.
  1358. * dest should always be 16 byte aligned.
  1359. **********************************/
  1360.  
  1361.  
  1362.  
  1363. DynamicAssembledCode FilteredResizeV::GenerateResizer(int gen_plane, bool aligned, IScriptEnvironment* env) {
  1364.  __declspec(align(8)) static const __int64 FPround           = 0x0000200000002000; // 16384/2
  1365.  __declspec(align(8)) static const __int64 FProundSSSE3      = 0x0020002000200020; // 128/2
  1366.  __declspec(align(8)) static const __int64 UnpackByteShuffle = 0x0100010001000100;
  1367.  
  1368.  Assembler x86;   // This is the class that assembles the code.
  1369.  bool ssse3 = !!(env->GetCPUFlags() & CPUF_SSSE3);  // We have one version for SSSE3 and one for plain MMX.
  1370.  bool sse3  = !!(env->GetCPUFlags() & CPUF_SSE3);   // We have specialized load routine for SSE3.
  1371.  bool sse2  = !!(env->GetCPUFlags() & CPUF_SSE2);
  1372.  bool isse  = !!(env->GetCPUFlags() & CPUF_INTEGER_SSE);
  1373.  
  1374.  if (aligned && !sse2) // No fast aligned version without SSE2+
  1375.    return DynamicAssembledCode();
  1376.  
  1377.  int xloops = 0;
  1378.  int y = vi.height;
  1379.  
  1380.  int* array = (gen_plane == PLANAR_U || gen_plane == PLANAR_V) ? resampling_patternUV : resampling_pattern ;
  1381.  int fir_filter_size = array[0];
  1382.  int* cur = &array[1];
  1383.  
  1384.  if (vi.IsPlanar()) {
  1385.    xloops = vi.width >> vi.GetPlaneWidthSubsampling(gen_plane);
  1386.    y = y >> (vi.GetPlaneHeightSubsampling(gen_plane));
  1387.  } else {
  1388.    xloops = vi.BytesFromPixels(vi.width);
  1389.  }
  1390.  
  1391.  if (sse2)
  1392.    xloops = ((xloops+15) / 16) * 16;
  1393.  else
  1394.    xloops = (xloops+7) / 8;
  1395.  
  1396.  
  1397.  // Store registers
  1398.  x86.push(           eax);
  1399.  x86.push(           ebx);
  1400.  x86.push(           ecx);
  1401.  x86.push(           edx);
  1402.  x86.push(           esi);
  1403.  x86.push(           edi);
  1404.  x86.push(           ebp);
  1405.  
  1406.  if (fir_filter_size == 1) {                 // Fast PointResize
  1407. // eax ebx ecx edx esi edi ebp
  1408. // mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7
  1409. // xmm0 XMM1 xmm2 XMM3 xmm4 XMM5 xmm6 XMM7
  1410.    x86.mov(          edx, (int)cur);              // edx = &array[1] -> start_pos
  1411.    x86.mov(          ebx, dword_ptr[(int)&dst_pitch]);
  1412.    x86.mov(          ebp, dword_ptr[(int)&dstp]);
  1413.    x86.mov(          edi, y);                     // edi = vi.height
  1414.  
  1415.    x86.align(16);
  1416. x86.label("yloop");
  1417.    x86.mov(          esi, dword_ptr[(int)&yOfs2]);// int pitch_table[height] = {0, src_pitch, src_pitch*2, ...}
  1418.    x86.mov(          eax, dword_ptr[edx]);        // eax = *cur = start_pos
  1419.    x86.lea(          edx, dword_ptr[edx+(fir_filter_size*4)+4]); // cur += fir_filter_size+1
  1420.    x86.mov(          esi, dword_ptr[esi+eax*4]);  // esi = yOfs[*cur] = start_pos * src_pitch
  1421.    x86.mov(          eax, ebp);                   // eax = dstp
  1422.    x86.add(          esi, dword_ptr[(int)&srcp]); // esi = srcp + yOfs[*cur] = srcp + start_pos * src_pitch
  1423.    x86.add(          ebp, ebx);                   // dstp += dst_pitch
  1424.                
  1425.    if (sse2) {
  1426.      int ploops = xloops / 64;
  1427.      int plrem  = xloops % 64;
  1428.      if (!plrem && ploops) {
  1429.        ploops -=  1;
  1430.        plrem  += 64;
  1431.      }
  1432.      if (ploops>1) {
  1433.        x86.mov(      ecx, ploops);
  1434.        x86.align(16);
  1435. x86.label("xloop");
  1436.      }
  1437.      if (ploops) {
  1438.        if (aligned) {
  1439.          x86.movdqa( xmm0, xmmword_ptr[esi+ 0]);  // xmm0 = *(srcp2= srcp + x) = p|o|n|m|l|k|j|i|h|g|f|e|d|c|b|a
  1440.          x86.movdqa( xmm2, xmmword_ptr[esi+16]);
  1441.          x86.movdqa( xmm4, xmmword_ptr[esi+32]);
  1442.          x86.movdqa( xmm6, xmmword_ptr[esi+48]);
  1443.        } else if (sse3) {
  1444.          x86.lddqu(  xmm0, xmmword_ptr[esi+ 0]); // SSE3
  1445.          x86.lddqu(  xmm2, xmmword_ptr[esi+16]);
  1446.          x86.lddqu(  xmm4, xmmword_ptr[esi+32]);
  1447.          x86.lddqu(  xmm6, xmmword_ptr[esi+48]);
  1448.        } else {
  1449.          x86.movdqu( xmm0, xmmword_ptr[esi+ 0]);
  1450.          x86.movdqu( xmm2, xmmword_ptr[esi+16]);
  1451.          x86.movdqu( xmm4, xmmword_ptr[esi+32]);
  1452.          x86.movdqu( xmm6, xmmword_ptr[esi+48]);
  1453.        }
  1454.        x86.add(      esi, 64);
  1455.  
  1456.        x86.movdqa(   xmmword_ptr[eax+ 0], xmm0);   // dstp[x] = p|o|n|m|l|k|j|i|h|g|f|e|d|c|b|a
  1457.        x86.movdqa(   xmmword_ptr[eax+16], xmm2);
  1458.        x86.movdqa(   xmmword_ptr[eax+32], xmm4);
  1459.        x86.movdqa(   xmmword_ptr[eax+48], xmm6);
  1460.        x86.add(      eax, 64);
  1461.      }
  1462.      if (ploops>1)
  1463.        x86.loop(     "xloop");
  1464.      if (aligned) {
  1465.        if (plrem> 0) x86.movdqa( xmm0, xmmword_ptr[esi+ 0]);
  1466.        if (plrem>16) x86.movdqa( xmm2, xmmword_ptr[esi+16]);
  1467.        if (plrem>32) x86.movdqa( xmm4, xmmword_ptr[esi+32]);
  1468.        if (plrem>48) x86.movdqa( xmm6, xmmword_ptr[esi+48]);
  1469.      } else if (sse3) {
  1470.        if (plrem> 0) x86.lddqu(  xmm0, xmmword_ptr[esi+ 0]);
  1471.        if (plrem>16) x86.lddqu(  xmm2, xmmword_ptr[esi+16]);
  1472.        if (plrem>32) x86.lddqu(  xmm4, xmmword_ptr[esi+32]);
  1473.        if (plrem>48) x86.lddqu(  xmm6, xmmword_ptr[esi+48]);
  1474.      } else {
  1475.        if (plrem> 0) x86.movdqu( xmm0, xmmword_ptr[esi+ 0]);
  1476.        if (plrem>16) x86.movdqu( xmm2, xmmword_ptr[esi+16]);
  1477.        if (plrem>32) x86.movdqu( xmm4, xmmword_ptr[esi+32]);
  1478.        if (plrem>48) x86.movdqu( xmm6, xmmword_ptr[esi+48]);
  1479.      }
  1480.      if (plrem> 0) x86.movdqa(   xmmword_ptr[eax+ 0], xmm0);
  1481.      if (plrem>16) x86.movdqa(   xmmword_ptr[eax+16], xmm2);
  1482.      if (plrem>32) x86.movdqa(   xmmword_ptr[eax+32], xmm4);
  1483.      if (plrem>48) x86.movdqa(   xmmword_ptr[eax+48], xmm6);
  1484.    }
  1485.    else { // MMX
  1486.      int ploops = xloops / 8;
  1487.      int plrem  = xloops % 8;
  1488.      if (!plrem && ploops) {
  1489.        ploops -= 1;
  1490.        plrem  += 8;
  1491.      }
  1492.      if (ploops>1) {
  1493.        x86.mov(      ecx, ploops);
  1494.        x86.align(16);
  1495. x86.label("xloop");
  1496.      }
  1497.      if (ploops) {
  1498.        x86.movq(     mm0, qword_ptr[esi+ 0]);  // mm0 = *(srcp2= srcp + x) = h|g|f|e|d|c|b|a
  1499.        x86.movq(     mm1, qword_ptr[esi+ 8]);
  1500.        x86.movq(     mm2, qword_ptr[esi+16]);
  1501.        x86.movq(     mm3, qword_ptr[esi+24]);
  1502.        x86.movq(     mm4, qword_ptr[esi+32]);
  1503.        x86.movq(     mm5, qword_ptr[esi+40]);
  1504.        x86.movq(     mm6, qword_ptr[esi+48]);
  1505.        x86.movq(     mm7, qword_ptr[esi+56]);
  1506.        x86.add(      esi, 64);
  1507.  
  1508.        x86.movq(     qword_ptr[eax+ 0], mm0); // dstp[x] = h|g|f|e|d|c|b|a
  1509.        x86.movq(     qword_ptr[eax+ 8], mm1);
  1510.        x86.movq(     qword_ptr[eax+16], mm2);
  1511.        x86.movq(     qword_ptr[eax+24], mm3);
  1512.        x86.movq(     qword_ptr[eax+32], mm4);
  1513.        x86.movq(     qword_ptr[eax+40], mm5);
  1514.        x86.movq(     qword_ptr[eax+48], mm6);
  1515.        x86.movq(     qword_ptr[eax+56], mm7);
  1516.        x86.add(      eax, 64);
  1517.      }
  1518.      if (ploops>1)
  1519.        x86.loop(     "xloop");
  1520.      if (plrem>0) x86.movq( mm0, qword_ptr[esi+ 0]);
  1521.      if (plrem>1) x86.movq( mm1, qword_ptr[esi+ 8]);
  1522.      if (plrem>2) x86.movq( mm2, qword_ptr[esi+16]);
  1523.      if (plrem>3) x86.movq( mm3, qword_ptr[esi+24]);
  1524.      if (plrem>4) x86.movq( mm4, qword_ptr[esi+32]);
  1525.      if (plrem>5) x86.movq( mm5, qword_ptr[esi+40]);
  1526.      if (plrem>6) x86.movq( mm6, qword_ptr[esi+48]);
  1527.      if (plrem>7) x86.movq( mm7, qword_ptr[esi+56]);
  1528.  
  1529.      if (plrem>0) x86.movq( qword_ptr[eax+ 0], mm0);
  1530.      if (plrem>1) x86.movq( qword_ptr[eax+ 8], mm1);
  1531.      if (plrem>2) x86.movq( qword_ptr[eax+16], mm2);
  1532.      if (plrem>3) x86.movq( qword_ptr[eax+24], mm3);
  1533.      if (plrem>4) x86.movq( qword_ptr[eax+32], mm4);
  1534.      if (plrem>5) x86.movq( qword_ptr[eax+40], mm5);
  1535.      if (plrem>6) x86.movq( qword_ptr[eax+48], mm6);
  1536.      if (plrem>7) x86.movq( qword_ptr[eax+56], mm7);
  1537.    }
  1538.    x86.dec(        edi);                       // y -= 1
  1539.    x86.jnz(        "yloop");
  1540.  }
  1541.  else if (ssse3 && fir_filter_size <= 8) { // We will get too many rounding errors. Probably only lanczos etc
  1542.                                            // if taps parameter is large and very high downscale ratios.
  1543.    x86.mov(          edx, (int)cur);
  1544.    x86.mov(          ebp, dword_ptr[(int)&src_pitch]);
  1545.    x86.mov(          ebx, dword_ptr[(int)&dst_pitch]);
  1546.    x86.mov(          edi, y);
  1547.    x86.movq(         xmm6, qword_ptr[(int)&FProundSSSE3]);        // Rounder for final division. Not touched!
  1548.    x86.movq(         xmm0, qword_ptr[(int)&UnpackByteShuffle]);   // Rounder for final division. Not touched!
  1549.    x86.pxor(         xmm5, xmm5);                                 // zeroes
  1550.    x86.punpcklqdq(   xmm6, xmm6);
  1551.    x86.punpcklqdq(   xmm0, xmm0);
  1552.                      
  1553.    x86.align(16);    
  1554. x86.label("yloop");  
  1555.    x86.mov(          esi, dword_ptr[(int)&yOfs2]);
  1556.    x86.mov(          eax, dword_ptr[edx]);               // eax = *cur
  1557.    x86.add(          edx, 4);                            // cur++
  1558.    x86.mov(          esi, dword_ptr[esi+eax*4]);
  1559.    x86.xor(          ecx, ecx);                          // ecx = x = 0
  1560.    x86.add(          esi, dword_ptr[(int)&srcp]);        // esi = srcp + yOfs[*cur]
  1561.    x86.movdqa(       xmm1, xmm6);                        // Init with rounder
  1562.    x86.movdqa(       xmm7, xmm6);
  1563.                      
  1564.    x86.align(16);    
  1565. x86.label("xloop");  
  1566.    x86.lea(          eax, dword_ptr[esi+ecx]);           // eax = srcp2 = srcp + x
  1567.    if (aligned) {    
  1568.      x86.movdqa(     xmm4, xmmword_ptr[eax]);            // xmm4 = p|o|n|m|l|k|j|i|h|g|f|e|d|c|b|a
  1569.    } else if (sse3) {
  1570.      x86.lddqu(      xmm4, xmmword_ptr[eax]); // SSE3
  1571.    } else {          
  1572.      x86.movdqu(     xmm4, xmmword_ptr[eax]);
  1573.    }
  1574.  
  1575.    for (int i = 0; i< fir_filter_size; i++) {
  1576.      x86.movd(       xmm3, dword_ptr[edx+i*4]);          // mm3 = cur[b] = 0|co
  1577.      x86.movdqa(     xmm2, xmm4);
  1578.      x86.punpckhbw(  xmm4, xmm5);                        // mm4 = *srcp2 = 0p|0o|0n|0m|0l|0k|0j|0i
  1579.      x86.punpcklbw(  xmm2, xmm5);                        // mm2 = *srcp2 = 0h|0g|0f|0e|0d|0c|0b|0a
  1580.      x86.pshufb(     xmm3, xmm0);                        // Unpack coefficient to all words
  1581.      x86.psllw(      xmm2, 7);                           // Extend to signed word
  1582.      x86.psllw(      xmm4, 7);                           // Extend to signed word
  1583.      x86.add(        eax, ebp);                          // srcp2 += src_pitch
  1584.      x86.pmulhrsw(   xmm2, xmm3); // SSSE3               // Multiply [h|g|f|e|d|c|b|a] 14bit(coeff) x 16bit(signed) ->
  1585.      x86.pmulhrsw(   xmm3, xmm4); // SSSE3               // Multiply [p|o|n|m|l|k|j|i] 16bit signed and rounded result.
  1586.      if (i<fir_filter_size-1) {                          // Load early for next loop
  1587.        if (aligned)
  1588.          x86.movdqa( xmm4, xmmword_ptr[eax]);            // xmm4 = p|o|n|m|l|k|j|i|h|g|f|e|d|c|b|a
  1589.        else if (sse3)
  1590.          x86.lddqu(  xmm4, xmmword_ptr[eax]); // SSE3
  1591.        else
  1592.          x86.movdqu( xmm4, xmmword_ptr[eax]);
  1593.      }
  1594.      x86.paddsw(     xmm1, xmm2);                        // Accumulate: h|g|f|e|d|c|b|a (signed words)
  1595.      x86.paddsw(     xmm7, xmm3);                        // Accumulate: p|o|n|m|l|k|j|i
  1596.    }
  1597.    x86.psraw(        xmm1, 6);                           // Compensate fraction
  1598.    x86.psraw(        xmm7, 6);                           // Compensate fraction
  1599.    x86.mov(          eax, dword_ptr[(int)&dstp]);
  1600.    x86.packuswb(     xmm1, xmm7);                        // mm1 = p|o|n|m|l|k|j|i|h|g|f|e|d|c|b|a
  1601.    x86.add(          ecx, 16);
  1602.    x86.movdqa(       xmm7, xmm6);
  1603.    x86.movdqa(       xmmword_ptr[eax+ecx-16], xmm1);     // Dest should always be aligned.
  1604.    x86.cmp(          ecx, xloops);
  1605.    x86.movdqa(       xmm1, xmm6);                        // Init with rounder
  1606.    x86.jl(           "xloop");
  1607.  
  1608.    x86.add(          eax, ebx);
  1609.    x86.lea(          edx, dword_ptr[edx+(fir_filter_size*4)]); //cur += fir_filter_size
  1610.    x86.dec(          edi);
  1611.    x86.mov(          dword_ptr[(int)&dstp], eax);
  1612.    x86.jnz(          "yloop");
  1613.  }
  1614.  else if (sse2) {
  1615.  // eax ebx ecx edx esi edi ebp
  1616.  // xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7
  1617.    x86.mov(     edx, (int)cur);                  // edx = &array[1] -> start_pos
  1618.    x86.mov(     ebp, dword_ptr[(int)&src_pitch]);
  1619.    x86.mov(     ebx, dword_ptr[(int)&dst_pitch]);
  1620.    x86.mov(     edi, y);                         // edi = vi.height
  1621.  
  1622.    x86.align(16);
  1623. x86.label("yloop");
  1624.    x86.mov(     esi, dword_ptr[(int)&yOfs2]);    // int pitch_table[height] = {0, src_pitch, src_pitch*2, ...}
  1625.    x86.mov(     eax, dword_ptr[edx]);            // eax = *cur = start_pos
  1626.    x86.mov(     esi, dword_ptr[esi+eax*4]);      // esi = yOfs[*cur] = start_pos * src_pitch
  1627.    x86.add(     edx, 4);                         // cur++  (*cur = coeff[0])
  1628.    x86.add(     esi, dword_ptr[(int)&srcp]);     // esi = srcp + yOfs[*cur] = srcp + start_pos * src_pitch
  1629.    x86.xor(     ecx, ecx);                       // ecx = x = 0
  1630.  
  1631.    x86.align(16);
  1632. x86.label("xloop");
  1633.    x86.lea(          eax,  dword_ptr[esi+ecx]);  // eax = srcp2 = srcp + x
  1634.    x86.movd(         xmm7, dword_ptr[(int)&FPround]);// Rounder for final division.
  1635.    if (aligned)
  1636.      x86.movdqa(     xmm0, xmmword_ptr[eax]);    // xmm0 = *srcp2 = p|o|n|m|l|k|j|i|h|g|f|e|d|c|b|a
  1637.    else if (sse3)
  1638.      x86.lddqu(      xmm0, xmmword_ptr[eax]); // SSE3
  1639.    else
  1640.      x86.movdqu(     xmm0, xmmword_ptr[eax]);
  1641.    x86.pshufd(       xmm7, xmm7, 0x00);          // totalPONM
  1642.    x86.movdqa(       xmm6, xmm7);                // totalLKJI
  1643.    x86.movdqa(       xmm5, xmm7);                // totalHGFE
  1644.    x86.movdqa(       xmm4, xmm7);                // totalDCBA
  1645.    int i=0;
  1646.    for ( ; i < fir_filter_size/2; i++) { // Doing row pairs
  1647.      if (aligned)
  1648.        x86.movdqa(     xmm2, xmmword_ptr[eax+ebp]);// xmm2 = *(srcp2+src_pitch) = P|O|N|M|L|K|J|I|H|G|F|E|D|C|B|A
  1649.      else if (sse3)
  1650.        x86.lddqu(      xmm2, xmmword_ptr[eax+ebp]); // SSE3
  1651.      else
  1652.        x86.movdqu(     xmm2, xmmword_ptr[eax+ebp]);
  1653.  
  1654.      x86.movq(       xmm3, qword_ptr[edx+i*8]);  // xmm3 = cur[b] = 00|00|--coeff[i+1]|--coeff[i]
  1655.      x86.lea(        eax,  dword_ptr[eax+ebp*2]);// srcp2 += src_pitch*2
  1656.      x86.movdqa(     xmm1, xmm0);                // xmm1                      = p|o|n|m|l|k|j|i|h|g|f|e|d|c|b|a
  1657.      x86.packssdw(   xmm3, xmm3);                // xmm3 = 00|00|00|00|CO|co|CO|co
  1658.  
  1659.      x86.punpcklbw(  xmm0, xmm2);                // xmm0 = Hh|Gg|Ff|Ee|Dd|Cc|Bb|Aa
  1660.      x86.punpckhbw(  xmm1, xmm2);                // xmm1 = Pp|Oo|Nn|Mm|Ll|Kk|Jj|Ii
  1661.      x86.pshufd(     xmm3, xmm3, 0x00);          // xmm3 = CO|co|CO|co|CO|co|CO|co
  1662.  
  1663.      x86.punpckhbw(  xmm2, xmm0);                // xmm2 = HP|hO|GN|gM|FL|fK|EJ|eI
  1664.      x86.punpcklbw(  xmm0, xmm0);                // xmm0 = DD|dd|CC|cc|BB|bb|AA|aa
  1665.      x86.psrlw(      xmm2, 8);                   // xmm2 = 0H|0h|0G|0g|0F|0f|0E|0e
  1666.      x86.psrlw(      xmm0, 8);                   // xmm0 = 0D|0d|0C|0c|0B|0b|0A|0a
  1667.  
  1668.      x86.pmaddwd(    xmm2, xmm3);                // xmm2 =  H*CO+h*co|G*CO+g*co|F*CO+f*co|E*CO+e*co
  1669.      x86.pmaddwd(    xmm0, xmm3);                // xmm0 =  D*CO+d*co|C*CO+c*co|B*CO+b*co|A*CO+a*co
  1670.      x86.paddd(      xmm5, xmm2);                // accumulateHGFE
  1671.      x86.paddd(      xmm4, xmm0);                // accumulateDCBA
  1672.  
  1673.      x86.pxor(       xmm0, xmm0);
  1674.      x86.movdqa(     xmm2, xmm1);                // xmm2 = Pp|Oo|Nn|Mm|Ll|Kk|Jj|Ii
  1675.      x86.punpcklbw(  xmm1, xmm0);                // xmm1 = 0L|0l|0K|0k|0J|0j|0I|0i
  1676.      x86.punpckhbw(  xmm2, xmm0);                // xmm2 = 0P|0p|0O|0o|0N|0n|0M|0m
  1677.  
  1678.      if (i*2 < fir_filter_size-2) {              // Load early for next loop
  1679.        if (aligned)
  1680.          x86.movdqa( xmm0, xmmword_ptr[eax]);    // xmm0 = *srcp2 = p|o|n|m|l|k|j|i|h|g|f|e|d|c|b|a
  1681.        else if (sse3)
  1682.          x86.lddqu(  xmm0, xmmword_ptr[eax]); // SSE3
  1683.        else
  1684.          x86.movdqu( xmm0, xmmword_ptr[eax]);
  1685.      }
  1686.      x86.pmaddwd(    xmm1, xmm3);                // xmm1 =  L*CO+l*co|K*CO+k*co|J*CO+j*co|I*CO+i*co
  1687.      x86.pmaddwd(    xmm2, xmm3);                // xmm4 =  P*CO+p*co|O*CO+o*co|N*CO+n*co|M*CO+m*co
  1688.      x86.paddd(      xmm6, xmm1);                // accumulateLKJI
  1689.      x86.paddd(      xmm7, xmm2);                // accumulatePONM
  1690.    }
  1691.    if (i*2 < fir_filter_size) { // Do last odd row
  1692.      x86.movd(       xmm3, dword_ptr[edx+i*8]);  // xmm3 = cur[b] = 00|00|00|--coeff[i]
  1693.      x86.pxor(       xmm2, xmm2);
  1694.      x86.punpckhbw(  xmm1, xmm0);                // xmm1 = p.|o.|n.|m.|l.|k.|j.|i.
  1695.      x86.pshufd(     xmm3, xmm3, 0x00);          // xmm3 = --co|--co|--co|--co
  1696.      x86.punpcklbw(  xmm0, xmm2);                // xmm0 = 0h|0g|0f|0e|0d|0c|0b|0a
  1697.      x86.pslld(      xmm3, 16);                  // xmm3 = co|00|co|00|co|00|co|00
  1698.      x86.psrlw(      xmm1, 8);                   // xmm1 = 0p|0o|0n|0m|0l|0k|0j|0i
  1699.      x86.punpckhwd(  xmm2, xmm0);                // xmm2 = 0h|..|0g|..|0f|..|0e|..
  1700.      x86.punpcklwd(  xmm0, xmm0);                // xmm0 = 0d|0d|0c|0c|0b|0b|0a|0a
  1701.      x86.pmaddwd(    xmm2, xmm3);                // xmm2 =  h*co|g*co|f*co|e*co
  1702.      x86.pmaddwd(    xmm0, xmm3);                // xmm0 =  d*co|c*co|b*co|a*co
  1703.      x86.paddd(      xmm5, xmm2);                // accumulateHGFE
  1704.      x86.paddd(      xmm4, xmm0);                // accumulateDCBA
  1705.      x86.punpckhwd(  xmm2, xmm1);                // xmm2 = 0p|..|0o|..|0n|..|0m|..
  1706.      x86.punpcklwd(  xmm1, xmm1);                // xmm1 = 0l|0l|0k|0k|0j|0j|0i|0i
  1707.      x86.pmaddwd(    xmm2, xmm3);                // xmm4 =  p*co|o*co|n*co|m*co
  1708.      x86.pmaddwd(    xmm1, xmm3);                // xmm1 =  l*co|k*co|j*co|i*co
  1709.      x86.paddd(      xmm7, xmm2);                // accumulatePONM
  1710.      x86.paddd(      xmm6, xmm1);                // accumulateLKJI
  1711.    }
  1712.    x86.psrad(        xmm4, 14);                  // 14 bits -> 16bit fraction [--FF....|--FF....]
  1713.    x86.psrad(        xmm5, 14);                  // compensate the fact that FPScale = 16384
  1714.    x86.psrad(        xmm6, 14);
  1715.    x86.psrad(        xmm7, 14);
  1716.    x86.packssdw(     xmm4, xmm5);                // xmm4 = 0h|0g|0f|0e|0d|0c|0b|0a
  1717.    x86.mov(          eax, dword_ptr[(int)&dstp]);
  1718.    x86.packssdw(     xmm6, xmm7);                // xmm6 = 0p|0o|0n|0m|0l|0k|0j|0i
  1719.    x86.add(          ecx, 16);                   // x += 16
  1720.    x86.packuswb(     xmm4, xmm6);                // xmm4 = p|o|n|m|l|k|j|i|h|g|f|e|d|c|b|a
  1721.    x86.cmp(          ecx, xloops);
  1722.    x86.movdqa(       xmmword_ptr[eax+ecx-16], xmm4); // dstp[x] = p|o|n|m|l|k|j|i|h|g|f|e|d|c|b|a
  1723.    x86.jnz(          "xloop");
  1724.                    
  1725.    x86.lea(          edx, dword_ptr[edx+(fir_filter_size*4)]); // cur += fir_filter_size
  1726.    x86.add(          eax, ebx);                  // dstp += dst_pitch
  1727.    x86.dec(          edi);                       // y -= 1
  1728.    x86.mov(          dword_ptr[(int)&dstp], eax);
  1729.    x86.jnz(          "yloop");
  1730.  }
  1731.  else {
  1732.  // eax ebx ecx edx esi edi ebp
  1733.  // mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7
  1734.    x86.mov(        edx, (int)cur);              // edx = &array[1] -> start_pos
  1735.    x86.mov(        ebp, dword_ptr[(int)&src_pitch]);
  1736.    x86.mov(        ebx, dword_ptr[(int)&dst_pitch]);
  1737.    x86.mov(        edi, y);                     // edi = vi.height
  1738.  
  1739.    x86.align(16);
  1740. x86.label("yloop");
  1741.    x86.mov(        esi, dword_ptr[(int)&yOfs2]);// int pitch_table[height] = {0, src_pitch, src_pitch*2, ...}
  1742.    x86.mov(        eax, dword_ptr[edx]);        // eax = *cur = start_pos
  1743.    x86.mov(        esi, dword_ptr[esi+eax*4]);  // esi = yOfs[*cur] = start_pos * src_pitch
  1744.    x86.add(        edx, 4);                     // cur++  (*cur = coeff[0])
  1745.    x86.add(        esi, dword_ptr[(int)&srcp]); // esi = srcp + yOfs[*cur] = srcp + start_pos * src_pitch
  1746.    x86.xor(        ecx, ecx);                   // ecx = x = 0
  1747.  
  1748.    x86.align(16);
  1749. x86.label("xloop");
  1750.    x86.lea(        eax, qword_ptr[esi+ecx*8]);  // eax = srcp2 = srcp + x
  1751.    x86.movq(       mm7, qword_ptr[(int)&FPround]);// totalHG = Rounder for final division.
  1752.    x86.movq(       mm0, qword_ptr[eax]);        // mm0 = *srcp2             = h|g|f|e|d|c|b|a
  1753.    x86.movq(       mm6, mm7);                   // totalFE
  1754.    x86.movq(       mm5, mm7);                   // totalDC
  1755.    x86.movq(       mm4, mm7);                   // totalBA
  1756.    int i=0;
  1757.    for ( ; i < fir_filter_size/2; i++) { // Doing row pairs
  1758.      x86.movq(       mm2, qword_ptr[eax+ebp]);  // mm2 = *(srcp2+src_pitch) = H|G|F|E|D|C|B|A
  1759.      x86.movq(       mm3, qword_ptr[edx+i*8]);  // mm3 = cur[b] = --coeff[i+1]|--coeff[i]
  1760.      x86.lea(        eax, qword_ptr[eax+ebp*2]);// srcp2 += src_pitch*2
  1761.      x86.movq(       mm1, mm0);                 // mm1                      = h|g|f|e|d|c|b|a
  1762.      x86.packssdw(   mm3, mm3);                 // mm3 = CO|co|CO|co
  1763.  
  1764.      x86.punpcklbw(  mm0, mm2);                 // mm0 = Dd|Cc|Bb|Aa
  1765.      x86.punpckhbw(  mm1, mm2);                 // mm1 = Hh|Gg|Ff|Ee
  1766.  
  1767.      x86.punpckhbw(  mm2, mm0);                 // mm2 = DH|dG|CF|cE
  1768.      x86.punpcklbw(  mm0, mm0);                 // mm0 = BB|bb|AA|aa
  1769.      x86.psrlw(      mm2, 8);                   // mm2 = 0D|0d|0C|0c
  1770.      x86.psrlw(      mm0, 8);                   // mm0 = 0B|0b|0A|0a
  1771.  
  1772.      x86.pmaddwd(    mm2, mm3);                 // mm2 = D*CO+d*co|C*CO+c*co
  1773.      x86.pmaddwd(    mm0, mm3);                 // mm0 = B*CO+b*co|A*CO+a*co
  1774.      x86.paddd(      mm5, mm2);                 // accumulateDC
  1775.      x86.paddd(      mm4, mm0);                 // accumulateBA
  1776.  
  1777.      x86.pxor(       mm0, mm0);
  1778.      x86.movq(       mm2, mm1);                 // mm2 = Hh|Gg|Ff|Ee
  1779.      x86.punpcklbw(  mm1, mm0);                 // mm1 = 0F|0f|0E|0e
  1780.      x86.punpckhbw(  mm2, mm0);                 // mm2 = 0H|0h|0G|0g
  1781.  
  1782.      if (i*2 < fir_filter_size-2)               // Load early for next loop
  1783.        x86.movq(     mm0, qword_ptr[eax]);      // mm0 = *srcp2             = h|g|f|e|d|c|b|a
  1784.  
  1785.      x86.pmaddwd(    mm1, mm3);                 // mm1 = F*CO+f*co|E*CO+e*co
  1786.      x86.pmaddwd(    mm2, mm3);                 // mm2 = H*CO+h*co|G*CO+g*co
  1787.      x86.paddd(      mm6, mm1);                 // accumulateFE
  1788.      x86.paddd(      mm7, mm2);                 // accumulateHG
  1789.    }
  1790.    if (i*2 < fir_filter_size) { // Do last odd row
  1791.      x86.movd(       mm3, dword_ptr[edx+i*8]);  // mm3 = cur[b] = 0|--coeff[i]
  1792.      x86.pxor(       mm2, mm2);
  1793.      x86.punpckhbw(  mm1, mm0);                 // mm1 = h.|g.|f.|e.
  1794.      if (isse) {
  1795.        x86.punpcklbw(mm0, mm2);                 // mm0 = 0d|0c|0b|0a
  1796.        x86.pshufw(   mm3, mm3, 0x33);           // mm3 = co|00|co|00
  1797.      } else {
  1798.        x86.punpckldq(mm3, mm3);                 // mm3 = --co|--co
  1799.        x86.punpcklbw(mm0, mm2);                 // mm0 = 0d|0c|0b|0a
  1800.        x86.pslld(    mm3, 16);                  // mm3 = co|00|co|00
  1801.      }
  1802.      x86.psrlw(      mm1, 8);                   // mm1 = 0h|0g|0f|0e
  1803.      x86.punpckhwd(  mm2, mm0);                 // mm2 = 0d|..|0c|..
  1804.      x86.punpcklwd(  mm0, mm0);                 // mm0 = 0b|0b|0a|0a
  1805.      x86.pmaddwd(    mm2, mm3);                 // mm2 =  d*co|c*co
  1806.      x86.pmaddwd(    mm0, mm3);                 // mm0 =  b*co|a*co
  1807.      x86.paddd(      mm5, mm2);                 // accumulateDC
  1808.      x86.paddd(      mm4, mm0);                 // accumulateBA
  1809.      x86.punpckhwd(  mm2, mm1);                 // mm2 = 0h|..|0g|..
  1810.      x86.punpcklwd(  mm1, mm1);                 // mm1 = 0f|0f|0e|0e
  1811.      x86.pmaddwd(    mm2, mm3);                 // mm2 =  h*co|g*co
  1812.      x86.pmaddwd(    mm1, mm3);                 // mm1 =  f*co|e*co
  1813.      x86.paddd(      mm7, mm2);                 // accumulateHG
  1814.      x86.paddd(      mm6, mm1);                 // accumulateFE
  1815.    }
  1816.    x86.psrad(      mm4, 14);                    // 14 bits -> 16bit fraction [--FF....|--FF....]
  1817.    x86.psrad(      mm5, 14);                    // compensate the fact that FPScale = 16384
  1818.    x86.psrad(      mm6, 14);
  1819.    x86.psrad(      mm7, 14);
  1820.    x86.packssdw(   mm4, mm5);                   // mm4 = 0d|0c|0b|0a
  1821.    x86.mov(        eax, dword_ptr[(int)&dstp]);
  1822.    x86.packssdw(   mm6, mm7);                   // mm6 = 0h|0g|0f|0e
  1823.    x86.inc(        ecx);                        // x += 1
  1824.    x86.packuswb(   mm4, mm6);                   // mm4 = h|g|f|e|d|c|b|a
  1825.    x86.cmp(        ecx, xloops);
  1826.    x86.movq(       qword_ptr[eax+ecx*8-8], mm4); // dstp[x] = h|g|f|e|d|c|b|a
  1827.    x86.jnz(        "xloop");
  1828.  
  1829.    x86.lea(        edx, dword_ptr[edx+(fir_filter_size*4)]);        // cur += fir_filter_size
  1830.    x86.add(        eax, ebx);                   // dstp += dst_pitch
  1831.    x86.dec(        edi);                        // y -= 1
  1832.    x86.mov(        dword_ptr[(int)&dstp], eax);
  1833.    x86.jnz(        "yloop");
  1834.  }
  1835.  // No more mmx for now
  1836.  x86.emms();
  1837.  // Restore registers
  1838.  x86.pop(          ebp);
  1839.  x86.pop(          edi);
  1840.  x86.pop(          esi);
  1841.  x86.pop(          edx);
  1842.  x86.pop(          ecx);
  1843.  x86.pop(          ebx);
  1844.  x86.pop(          eax);
  1845.  x86.ret();
  1846.  
  1847.  return DynamicAssembledCode(x86, env, "ResizeV: Dynamic code could not be compiled.");
  1848. }
  1849.  
  1850.  
  1851.  
  1852.  
  1853.  
  1854.  
  1855. /**********************************************
  1856. *******   Resampling Factory Methods   *******
  1857. **********************************************/
  1858.  
  1859. PClip FilteredResize::CreateResizeH(PClip clip, double subrange_left, double subrange_width, int target_width,
  1860.                    ResamplingFunction* func, IScriptEnvironment* env)
  1861. {
  1862.  const VideoInfo& vi = clip->GetVideoInfo();
  1863.  if (subrange_left == 0 && subrange_width == target_width && subrange_width == vi.width) {
  1864.    return clip;
  1865.  }
  1866.  
  1867.  if (subrange_left == int(subrange_left) && subrange_width == target_width
  1868.   && subrange_left >= 0 && subrange_left + subrange_width <= vi.width) {
  1869.    const int mask = (vi.IsYUV() && !vi.IsY8()) ? (1 << vi.GetPlaneWidthSubsampling(PLANAR_U)) - 1 : 0;
  1870.  
  1871.    if (((int(subrange_left) | int(subrange_width)) & mask) == 0)
  1872.      return new Crop(int(subrange_left), 0, int(subrange_width), vi.height, 0, clip, env);
  1873.  }
  1874.  return new FilteredResizeH(clip, subrange_left, subrange_width, target_width, func, env);
  1875. }
  1876.  
  1877.  
  1878. PClip FilteredResize::CreateResizeV(PClip clip, double subrange_top, double subrange_height, int target_height,
  1879.                    ResamplingFunction* func, IScriptEnvironment* env)
  1880. {
  1881.  const VideoInfo& vi = clip->GetVideoInfo();
  1882.  if (subrange_top == 0 && subrange_height == target_height && subrange_height == vi.height) {
  1883.    return clip;
  1884.  }
  1885.  
  1886.  if (subrange_top == int(subrange_top) && subrange_height == target_height
  1887.   && subrange_top >= 0 && subrange_top + subrange_height <= vi.height) {
  1888.    const int mask = (vi.IsYUV() && !vi.IsY8()) ? (1 << vi.GetPlaneHeightSubsampling(PLANAR_U)) - 1 : 0;
  1889.  
  1890.    if (((int(subrange_top) | int(subrange_height)) & mask) == 0)
  1891.      return new Crop(0, int(subrange_top), vi.width, int(subrange_height), 0, clip, env);
  1892.  }
  1893.  return new FilteredResizeV(clip, subrange_top, subrange_height, target_height, func, env);
  1894. }
  1895.  
  1896.  
  1897. PClip FilteredResize::CreateResize(PClip clip, int target_width, int target_height, const AVSValue* args,
  1898.                   ResamplingFunction* f, IScriptEnvironment* env)
  1899. {
  1900.     try {   // HIDE DAMN SEH COMPILER BUG!!!
  1901.  const VideoInfo& vi = clip->GetVideoInfo();
  1902.  const double subrange_left = args[0].AsFloat(0), subrange_top = args[1].AsFloat(0);
  1903.  
  1904.  double subrange_width = args[2].AsDblDef(vi.width), subrange_height = args[3].AsDblDef(vi.height);
  1905.  // Crop style syntax
  1906.  if (subrange_width  <= 0.0) subrange_width  = vi.width  - subrange_left + subrange_width;
  1907.  if (subrange_height <= 0.0) subrange_height = vi.height - subrange_top  + subrange_height;
  1908.  
  1909.  PClip result;
  1910.  // ensure that the intermediate area is maximal
  1911.  const double area_FirstH = subrange_height * target_width;
  1912.  const double area_FirstV = subrange_width * target_height;
  1913.  if (area_FirstH < area_FirstV)
  1914.  {
  1915.      result = CreateResizeV(clip, subrange_top, subrange_height, target_height, f, env);
  1916.      result = CreateResizeH(result, subrange_left, subrange_width, target_width, f, env);
  1917.  }
  1918.  else
  1919.  {
  1920.      result = CreateResizeH(clip, subrange_left, subrange_width, target_width, f, env);
  1921.      result = CreateResizeV(result, subrange_top, subrange_height, target_height, f, env);
  1922.  }
  1923.  return result;
  1924.     }
  1925.     catch (...) { throw; }
  1926. }
  1927.  
  1928. AVSValue __cdecl FilteredResize::Create_PointResize(AVSValue args, void*, IScriptEnvironment* env)
  1929. {
  1930.  return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), &args[3],
  1931.                       &PointFilter(), env );
  1932. }
  1933.  
  1934.  
  1935. AVSValue __cdecl FilteredResize::Create_BilinearResize(AVSValue args, void*, IScriptEnvironment* env)
  1936. {
  1937.  return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), &args[3],
  1938.                       &TriangleFilter(), env );
  1939. }
  1940.  
  1941.  
  1942. AVSValue __cdecl FilteredResize::Create_BicubicResize(AVSValue args, void*, IScriptEnvironment* env)
  1943. {
  1944.  return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), &args[5],
  1945.                       &MitchellNetravaliFilter(args[3].AsDblDef(1./3.), args[4].AsDblDef(1./3.)), env );
  1946. }
  1947.  
  1948. AVSValue __cdecl FilteredResize::Create_LanczosResize(AVSValue args, void*, IScriptEnvironment* env)
  1949. {
  1950.     try {   // HIDE DAMN SEH COMPILER BUG!!!
  1951.  return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), &args[3],
  1952.                       &LanczosFilter(args[7].AsInt(3)), env );
  1953.     }
  1954.     catch (...) { throw; }
  1955. }
  1956.  
  1957. AVSValue __cdecl FilteredResize::Create_Lanczos4Resize(AVSValue args, void*, IScriptEnvironment* env)
  1958. {
  1959.     try {   // HIDE DAMN SEH COMPILER BUG!!!
  1960.  return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), &args[3],
  1961.                       &LanczosFilter(4), env );
  1962.     }
  1963.     catch (...) { throw; }
  1964. }
  1965.  
  1966. AVSValue __cdecl FilteredResize::Create_BlackmanResize(AVSValue args, void*, IScriptEnvironment* env)
  1967. {
  1968.     try {   // HIDE DAMN SEH COMPILER BUG!!!
  1969.  return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), &args[3],
  1970.                       &BlackmanFilter(args[7].AsInt(4)), env );
  1971.     }
  1972.     catch (...) { throw; }
  1973. }
  1974.  
  1975. AVSValue __cdecl FilteredResize::Create_Spline16Resize(AVSValue args, void*, IScriptEnvironment* env)
  1976. {
  1977.  return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), &args[3],
  1978.                       &Spline16Filter(), env );
  1979. }
  1980.  
  1981. AVSValue __cdecl FilteredResize::Create_Spline36Resize(AVSValue args, void*, IScriptEnvironment* env)
  1982. {
  1983.  return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), &args[3],
  1984.                       &Spline36Filter(), env );
  1985. }
  1986.  
  1987. AVSValue __cdecl FilteredResize::Create_Spline64Resize(AVSValue args, void*, IScriptEnvironment* env)
  1988. {
  1989.  return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), &args[3],
  1990.                       &Spline64Filter(), env );
  1991. }
  1992.  
  1993. AVSValue __cdecl FilteredResize::Create_GaussianResize(AVSValue args, void*, IScriptEnvironment* env)
  1994. {
  1995.     try {   // HIDE DAMN SEH COMPILER BUG!!!
  1996.  return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), &args[3],
  1997.                       &GaussianFilter(args[7].AsFloat(30.0f)), env );
  1998.     }
  1999.     catch (...) { throw; }
  2000. }
  2001.  
  2002. AVSValue __cdecl FilteredResize::Create_SincResize(AVSValue args, void*, IScriptEnvironment* env)
  2003. {
  2004.     try {   // HIDE DAMN SEH COMPILER BUG!!!
  2005.  return CreateResize( args[0].AsClip(), args[1].AsInt(), args[2].AsInt(), &args[3],
  2006.                       &SincFilter(args[7].AsInt(4)), env );
  2007.     }
  2008.     catch (...) { throw; }
  2009. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement