// VirtualDub - Video processing and capture application // Graphics support library // Copyright (C) 1998-2009 Avery Lee // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include #include #include "blt_spanutils_x86.h" #include "resample_stages_x86.h" #include #ifdef _MSC_VER #pragma warning(disable: 4799) // warning C4799: function 'vdasm_resize_table_row_8_k8_4x_MMX' has no EMMS instruction #endif /////////////////////////////////////////////////////////////////////////////// extern "C" void vdasm_resize_table_row_8_k8_4x_SSE41(void *dst, const void *src, uint32 width, const void *kernel); extern "C" void vdasm_resize_table_row_8_k16_4x_SSE41(void *dst, const void *src, uint32 width, const void *kernel); extern "C" void vdasm_resize_table_row_8_SSE41(void *dst, const void *src, uint32 width, const void *kernel, uint32 kwidth); extern "C" void vdasm_resize_table_col_8_k2_SSE41(void *dst, const void *const *srcs, uint32 width, const void *kernel); extern "C" void vdasm_resize_table_col_8_k4_SSE41(void *dst, const void *const *srcs, uint32 width, const void *kernel); /////////////////////////////////////////////////////////////////////////////// namespace { struct ScaleInfo { void *dst; uintptr src; uint32 accum; uint32 fracinc; sint32 intinc; uint32 count; }; extern "C" void vdasm_resize_point32(const ScaleInfo *); } int VDResamplerSeparablePointRowStageX86::GetWindowSize() const {return 1;} void VDResamplerSeparablePointRowStageX86::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { ScaleInfo info; info.dst = (uint32 *)dst + w; info.src = ((uintptr)src >> 2) + (u>>16); info.accum = u<<16; info.fracinc = dudx << 16; info.intinc = (sint32)dudx >> 16; info.count = -(sint32)w*4; vdasm_resize_point32(&info); } /////////////////////////////////////////////////////////////////////////////// void VDResamplerRowStageSeparableLinear8_phaseZeroStepHalf_ISSE::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { uint8 *dst = (uint8 *)dst0; const uint8 *src = (const uint8 *)src0; nsVDPixmapSpanUtils::horiz_expand2x_coaligned_ISSE(dst, src, w); } /////////////////////////////////////////////////////////////////////////////// extern "C" void vdasm_resize_point32_MMX(const ScaleInfo *); extern "C" void vdasm_resize_interp_row_run_MMX(void *dst, const void *src, uint32 width, sint64 xaccum, sint64 x_inc); extern "C" void vdasm_resize_interp_col_run_MMX(void *dst, const void *src1, const void *src2, uint32 width, uint32 yaccum); extern "C" void vdasm_resize_ccint_row_MMX(void *dst, const void *src, uint32 count, uint32 xaccum, sint32 xinc, const void *tbl); extern "C" void vdasm_resize_ccint_col_MMX(void *dst, const void *src1, const void *src2, const void *src3, const void *src4, uint32 count, const void *tbl); extern "C" long vdasm_resize_table_col_MMX(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w, long frac); extern "C" long vdasm_resize_table_row_MMX(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac); int VDResamplerSeparablePointRowStageMMX::GetWindowSize() const {return 1;} void VDResamplerSeparablePointRowStageMMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { ScaleInfo info; info.dst = (uint32 *)dst + w; info.src = ((uintptr)src >> 2) + (u>>16); info.accum = u<<16; info.fracinc = dudx << 16; info.intinc = (sint32)dudx >> 16; info.count = -(sint32)w*4; vdasm_resize_point32_MMX(&info); } int VDResamplerSeparableLinearRowStageMMX::GetWindowSize() const {return 2;} void VDResamplerSeparableLinearRowStageMMX::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { vdasm_resize_interp_row_run_MMX(dst0, src0, w, (sint64)u << 16, (sint64)dudx << 16); } int VDResamplerSeparableLinearColStageMMX::GetWindowSize() const {return 2;} void VDResamplerSeparableLinearColStageMMX::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { vdasm_resize_interp_col_run_MMX(dst0, srcarray[0], srcarray[1], w, phase); } VDResamplerSeparableCubicRowStageMMX::VDResamplerSeparableCubicRowStageMMX(double A) : mFilterBank(1024) { sint32 *p = mFilterBank.data(); VDResamplerGenerateTable(p, VDResamplerCubicFilter(1.0, A)); VDResamplerSwizzleTable(p, 512); } int VDResamplerSeparableCubicRowStageMMX::GetWindowSize() const {return 4;} void VDResamplerSeparableCubicRowStageMMX::Process(void *dst0, const void *src0, uint32 w, uint32 u, uint32 dudx) { vdasm_resize_ccint_row_MMX(dst0, src0, w, u, dudx, mFilterBank.data()); } VDResamplerSeparableCubicColStageMMX::VDResamplerSeparableCubicColStageMMX(double A) : mFilterBank(1024) { sint32 *p = mFilterBank.data(); VDResamplerGenerateTable(p, VDResamplerCubicFilter(1.0, A)); VDResamplerSwizzleTable(p, 512); } int VDResamplerSeparableCubicColStageMMX::GetWindowSize() const {return 4;} void VDResamplerSeparableCubicColStageMMX::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { vdasm_resize_ccint_col_MMX(dst0, srcarray[0], srcarray[1], srcarray[2], srcarray[3], w, mFilterBank.data() + ((phase>>6)&0x3fc)); } VDResamplerSeparableTableRowStage8MMX::VDResamplerSeparableTableRowStage8MMX(const IVDResamplerFilter& filter) : VDResamplerRowStageSeparableTable32(filter) , mLastSrcWidth(0) , mLastDstWidth(0) , mLastU(0) , mLastDUDX(0) { mAlignedKernelWidth = (GetWindowSize() + 6) & ~3; mAlignedKernelSize = mAlignedKernelWidth + 4; } void VDResamplerSeparableTableRowStage8MMX::Init(const VDResamplerAxis& axis, uint32 srcw) { uint32 w = axis.dx_preclip + axis.dx_active + axis.dx_postclip + axis.dx_dualclip; if (mLastSrcWidth != srcw || mLastDstWidth != w || mLastU != axis.u || mLastDUDX != axis.dudx) { mLastSrcWidth = srcw; mLastDstWidth = w; mLastU = axis.u; mLastDUDX = axis.dudx; RedoRowFilters(axis, w, srcw); } } void VDResamplerSeparableTableRowStage8MMX::RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw) { int kstride = mFilterBank.size() >> 8; int ksize = mAlignedKernelWidth; int kesize = mAlignedKernelSize; mRowKernels.clear(); mRowKernelSize = w * kesize; mRowKernels.resize(mRowKernelSize * 4, 0); for(int byteOffset = 0; byteOffset < 4; ++byteOffset) { sint16 *dst = mRowKernels.data() + mRowKernelSize * byteOffset; int ksizeThisOffset = std::min(ksize, (byteOffset + srcw + 3) & ~3); mKernelSizeByOffset[byteOffset] = ksizeThisOffset; sint32 u = axis.u; sint32 uoffmin = -byteOffset; sint32 uoffmax = ((srcw + byteOffset + 3) & ~3) - byteOffset - ksizeThisOffset; for(uint32 i=0; i> 16; sint32 uoffset2 = ((uoffset + byteOffset) & ~3) - byteOffset; if (uoffset2 < uoffmin) uoffset2 = uoffmin; if (uoffset2 > uoffmax) uoffset2 = uoffmax; VDASSERT(uoffset2 + ksizeThisOffset <= (((sint32)srcw + byteOffset + 3) & ~3)); *(sint32 *)dst = uoffset2; dst += 2; *dst++ = 0; *dst++ = 0; uint32 phase = (u >> 8) & 255; const sint32 *src = &mFilterBank[kstride * phase]; sint32 start = 0; sint32 end = kstride; int dstoffset = uoffset - uoffset2; // check for filter kernel overlapping left source boundary if (uoffset < 0) start = -uoffset; // check for filter kernel overlapping right source boundary if (uoffset + end > (sint32)srcw) end = srcw - uoffset; VDASSERT(dstoffset + start >= 0); VDASSERT(dstoffset + end <= ksizeThisOffset); sint16 *dst2 = dst + dstoffset; dst += ksizeThisOffset; for(int j=start; j 0) dst2[start] = std::accumulate(src, src+start, dst2[start]); if (end < kstride) dst2[end - 1] = std::accumulate(src+end, src+kstride, dst2[end - 1]); u += axis.dudx; } } // swizzle rows where optimization is possible vdfastvector temp; int quads = w >> 2; int quadRemainder = w & 3; for(int byteOffset = 0; byteOffset < 4; ++byteOffset) { int ksizeThisOffset = mKernelSizeByOffset[byteOffset]; int kpairs = ksizeThisOffset >> 2; if (ksizeThisOffset < 8 || ksizeThisOffset > 12) { mbQuadOptimizationEnabled[byteOffset] = false; } else { ptrdiff_t unswizzledStride = (ksizeThisOffset >> 1) + 2; mbQuadOptimizationEnabled[byteOffset] = true; mTailOffset[byteOffset] = quads * (8 + ksizeThisOffset*4); uint32 *dst = (uint32 *)&mRowKernels[mRowKernelSize * byteOffset]; temp.resize(mRowKernelSize); memcpy(temp.data(), dst, mRowKernelSize*2); const uint32 *src0 = (const uint32 *)temp.data(); const uint32 *src1 = src0 + unswizzledStride; const uint32 *src2 = src1 + unswizzledStride; const uint32 *src3 = src2 + unswizzledStride; ptrdiff_t srcskip = unswizzledStride * 3; for(int q = 0; q < quads; ++q) { dst[0] = src0[0]; dst[1] = src1[0]; dst[2] = src2[0]; dst[3] = src3[0]; src0 += 2; src1 += 2; src2 += 2; src3 += 2; dst += 4; for(int p = 0; p < kpairs; ++p) { dst[0] = src0[0]; dst[1] = src0[1]; dst[2] = src1[0]; dst[3] = src1[1]; dst[4] = src2[0]; dst[5] = src2[1]; dst[6] = src3[0]; dst[7] = src3[1]; dst += 8; src0 += 2; src1 += 2; src2 += 2; src3 += 2; } src0 += srcskip; src1 += srcskip; src2 += srcskip; src3 += srcskip; } memcpy(dst, src0, unswizzledStride * 4 * quadRemainder); VDASSERT(dst + unswizzledStride * quadRemainder <= (void *)(mRowKernels.data() + (mRowKernelSize * (byteOffset + 1)))); } } } void __declspec(naked) vdasm_resize_table_row_8_k8_4x_MMX(void *dst, const void *src, uint32 width, const void *kernel) { static const __declspec(align(8)) __int64 kRound = 0x0000000000002000; __asm { push ebp push edi push esi push ebx pxor mm7, mm7 movq mm6, kRound mov ebp, [esp + 4 + 16] ;ebp = dst mov esi, [esp + 12 + 16] ;esi = width mov edi, [esp + 16 + 16] ;edi = kernel yloop: ;eax = temp ;ebx = temp ;ecx = temp ;edx = temp ;esi = horiz counter ;edi = filter list ;ebp = destination mov eax, [edi+0] mov ebx, [edi+4] mov ecx, [edi+8] mov edx, [esp+8+16] add eax, edx add ebx, edx add ecx, edx add edx, [edi+12] movd mm0, [eax] punpcklbw mm0, mm7 pmaddwd mm0, [edi+16] movd mm1, [ebx] punpcklbw mm1, mm7 pmaddwd mm1, [edi+24] movd mm2, [ecx] punpcklbw mm2, mm7 pmaddwd mm2, [edi+32] movd mm3, [edx] punpcklbw mm3, mm7 pmaddwd mm3, [edi+40] movd mm4, [eax+4] paddd mm0, mm6 movd mm5, [ebx+4] punpcklbw mm4, mm7 paddd mm1, mm6 pmaddwd mm4, [edi+48] punpcklbw mm5, mm7 paddd mm2, mm6 pmaddwd mm5, [edi+56] paddd mm3, mm6 paddd mm0, mm4 paddd mm1, mm5 movd mm4, [ecx+4] punpcklbw mm4, mm7 pmaddwd mm4, [edi+64] movd mm5, [edx+4] punpcklbw mm5, mm7 pmaddwd mm5, [edi+72] paddd mm2, mm4 paddd mm3, mm5 movq mm4, mm0 punpckldq mm0, mm1 movq mm5, mm2 punpckldq mm2, mm3 punpckhdq mm4, mm1 punpckhdq mm5, mm3 paddd mm0, mm4 paddd mm2, mm5 psrad mm0, 14 psrad mm2, 14 packssdw mm0, mm2 packuswb mm0, mm0 add edi, 80 movd [ebp], mm0 add ebp, 4 sub esi, 1 jne yloop pop ebx pop esi pop edi pop ebp ret } } void __declspec(naked) vdasm_resize_table_row_8_k12_4x_MMX(void *dst, const void *src, uint32 width, const void *kernel) { static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; __asm { push ebp push edi push esi push ebx pxor mm7, mm7 movq mm6, kRound mov ebp, [esp + 4 + 16] ;ebp = dst mov esi, [esp + 12 + 16] ;esi = width mov edi, [esp + 16 + 16] ;edi = kernel yloop: ;eax = temp ;ebx = temp ;ecx = temp ;edx = temp ;esi = horiz counter ;edi = filter list ;ebp = destination mov eax, [edi+0] mov ebx, [edi+4] mov ecx, [edi+8] mov edx, [esp+8+16] add eax, edx add ebx, edx add ecx, edx add edx, [edi+12] movd mm0, [eax] punpcklbw mm0, mm7 pmaddwd mm0, [edi+16] movd mm1, [ebx] punpcklbw mm1, mm7 pmaddwd mm1, [edi+24] movd mm2, [ecx] punpcklbw mm2, mm7 pmaddwd mm2, [edi+32] movd mm3, [edx] punpcklbw mm3, mm7 pmaddwd mm3, [edi+40] movd mm4, [eax+4] punpcklbw mm4, mm7 pmaddwd mm4, [edi+48] movd mm5, [ebx+4] punpcklbw mm5, mm7 pmaddwd mm5, [edi+56] paddd mm0, mm4 paddd mm1, mm5 movd mm4, [ecx+4] punpcklbw mm4, mm7 movd mm5, [edx+4] pmaddwd mm4, [edi+64] punpcklbw mm5, mm7 paddd mm2, mm4 pmaddwd mm5, [edi+72] movd mm4, [eax+8] punpcklbw mm4, mm7 paddd mm3, mm5 movd mm5, [ebx+8] punpcklbw mm5, mm7 pmaddwd mm4, [edi+80] paddd mm0, mm4 movd mm4, [ecx+8] pmaddwd mm5, [edi+88] paddd mm1, mm5 punpcklbw mm4, mm7 pmaddwd mm4, [edi+96] movd mm5, [edx+8] punpcklbw mm5, mm7 pmaddwd mm5, [edi+104] paddd mm2, mm4 paddd mm3, mm5 movq mm4, mm0 punpckldq mm0, mm1 movq mm5, mm2 punpckldq mm2, mm3 punpckhdq mm4, mm1 punpckhdq mm5, mm3 paddd mm0, mm4 paddd mm2, mm5 paddd mm0, mm6 paddd mm2, mm6 psrad mm0, 14 psrad mm2, 14 packssdw mm0, mm2 packuswb mm0, mm0 add edi, 112 movd [ebp], mm0 add ebp, 4 sub esi, 1 jne yloop pop ebx pop esi pop edi pop ebp ret } } void __declspec(naked) vdasm_resize_table_row_8_MMX(void *dst, const void *src, uint32 width, const void *kernel, uint32 kwidth) { static const __declspec(align(8)) __int64 kRound = 0x0000000000002000; __asm { push ebp push edi push esi push ebx pxor mm7, mm7 movq mm6, kRound mov edi, [esp + 4 + 16] ;edi = dst mov ebx, [esp + 8 + 16] ;ebx = src mov ebp, [esp + 12 + 16] ;ebp = width mov edx, [esp + 16 + 16] ;edx = kernel yloop: ;eax = temp ;ebx = source base address ;ecx = (temp) source ;edx = filter list ;esi = (temp) kernel width ;edi = destination ;ebp = horiz counter mov eax, [edx] add edx, 8 lea ecx, [ebx + eax] mov esi, [esp + 20 + 16] ;esi = kernel width movq mm2, mm6 xloop: movd mm0, [ecx] punpcklbw mm0, mm7 add ecx, 4 pmaddwd mm0, [edx] paddd mm2, mm0 add edx, 8 sub esi, 4 jne xloop punpckldq mm0, mm2 paddd mm0, mm2 psrad mm0, 14 psrlq mm0, 32 packssdw mm0, mm0 packuswb mm0, mm0 movd eax, mm0 mov [edi], al add edi, 1 sub ebp, 1 jne yloop pop ebx pop esi pop edi pop ebp ret } } void VDResamplerSeparableTableRowStage8MMX::Process(void *dst, const void *src, uint32 w) { int byteOffset = (int)(ptrdiff_t)src & 3; const sint16 *ksrc = mRowKernels.data() + (mRowKernelSize * byteOffset); #if 0 int kwidth = mAlignedKernelWidth; uint8 *dst2 = (uint8 *)dst; do { int offset = ksrc[0]; ksrc += 4; const uint8 *src2 = (const uint8 *)src + offset; sint32 accum = 0x8000; for(int i=0; i>= 14; accum &= ~(accum >> 31); accum |= (255 - accum) >> 31; *dst2++ = (uint8)accum; } while(--w); #else int ksize = mKernelSizeByOffset[byteOffset]; if (mbQuadOptimizationEnabled[byteOffset]) { if (w >= 4) { if (ksize == 12) { vdasm_resize_table_row_8_k12_4x_MMX(dst, src, w >> 2, ksrc); #if 0 int w4 = w >> 2; uint8 *dst2 = (uint8 *)dst; const uint8 *src2 = (const uint8 *)src; const sint16 *ksrc2 = ksrc; do { int off0 = ksrc2[0]; int off1 = ksrc2[2]; int off2 = ksrc2[4]; int off3 = ksrc2[6]; const uint8 *d0 = src2 + off0; const uint8 *d1 = src2 + off1; const uint8 *d2 = src2 + off2; const uint8 *d3 = src2 + off3; int acc0 = 0; int acc1 = 0; int acc2 = 0; int acc3 = 0; acc0 += d0[ 0]*ksrc2[ 8] + d0[ 1]*ksrc2[ 9] + d0[ 2]*ksrc2[ 10] + d0[ 3]*ksrc2[ 11] + d0[ 4]*ksrc2[ 24] + d0[ 5]*ksrc2[ 25] + d0[ 6]*ksrc2[ 26] + d0[ 7]*ksrc2[ 27] + d0[ 8]*ksrc2[ 40] + d0[ 9]*ksrc2[ 41] + d0[10]*ksrc2[ 42] + d0[11]*ksrc2[ 43]; acc0 = (acc0 + 0x2000) >> 14; if (acc0 < 0) acc0 = 0; else if (acc0 > 255) acc0 = 255; acc1 += d1[ 0]*ksrc2[ 12] + d1[ 1]*ksrc2[ 13] + d1[ 2]*ksrc2[ 14] + d1[ 3]*ksrc2[ 15] + d1[ 4]*ksrc2[ 28] + d1[ 5]*ksrc2[ 29] + d1[ 6]*ksrc2[ 30] + d1[ 7]*ksrc2[ 31] + d1[ 8]*ksrc2[ 44] + d1[ 9]*ksrc2[ 45] + d1[10]*ksrc2[ 46] + d1[11]*ksrc2[ 47]; acc1 = (acc1 + 0x2000) >> 14; if (acc1 < 0) acc1 = 0; else if (acc1 > 255) acc1 = 255; acc2 += d2[ 0]*ksrc2[ 16] + d2[ 1]*ksrc2[ 17] + d2[ 2]*ksrc2[ 18] + d2[ 3]*ksrc2[ 19] + d2[ 4]*ksrc2[ 32] + d2[ 5]*ksrc2[ 33] + d2[ 6]*ksrc2[ 34] + d2[ 7]*ksrc2[ 35] + d2[ 8]*ksrc2[ 48] + d2[ 9]*ksrc2[ 49] + d2[10]*ksrc2[ 50] + d2[11]*ksrc2[ 51]; acc2 = (acc2 + 0x2000) >> 14; if (acc2 < 0) acc2 = 0; else if (acc2 > 255) acc2 = 255; acc3 += d3[ 0]*ksrc2[ 20] + d3[ 1]*ksrc2[ 21] + d3[ 2]*ksrc2[ 22] + d3[ 3]*ksrc2[ 23] + d3[ 4]*ksrc2[ 36] + d3[ 5]*ksrc2[ 37] + d3[ 6]*ksrc2[ 38] + d3[ 7]*ksrc2[ 39] + d3[ 8]*ksrc2[ 52] + d3[ 9]*ksrc2[ 53] + d3[10]*ksrc2[ 54] + d3[11]*ksrc2[ 55]; acc3 = (acc3 + 0x2000) >> 14; if (acc3 < 0) acc3 = 0; else if (acc3 > 255) acc3 = 255; ksrc2 += 56; dst2[0] = (uint8)acc0; dst2[1] = (uint8)acc1; dst2[2] = (uint8)acc2; dst2[3] = (uint8)acc3; dst2 += 4; } while(--w4); #endif } else vdasm_resize_table_row_8_k8_4x_MMX(dst, src, w >> 2, ksrc); } if (w & 3) vdasm_resize_table_row_8_MMX((char *)dst + (w & ~3), src, w & 3, ksrc + mTailOffset[byteOffset], ksize); } else if (w) { vdasm_resize_table_row_8_MMX(dst, src, w, ksrc, ksize); } #endif } void VDResamplerSeparableTableRowStage8MMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); } VDResamplerSeparableTableRowStageMMX::VDResamplerSeparableTableRowStageMMX(const IVDResamplerFilter& filter) : VDResamplerRowStageSeparableTable32(filter) { VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); } void VDResamplerSeparableTableRowStageMMX::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); } /////////////////////////////////////////////////////////////////////////// VDResamplerSeparableTableColStage8MMX::VDResamplerSeparableTableColStage8MMX(const IVDResamplerFilter& filter) : VDResamplerColStageSeparableTable8(filter) { VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); } void __declspec(naked) vdasm_resize_table_col_8_k2_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel) { static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; __asm { push ebp push edi push esi push ebx pxor mm7, mm7 movq mm6, kRound mov esi, [esp + 4 + 16] ;esi = dst mov edi, [esp + 16 + 16] ;edi = kernel mov ebp, [esp + 12 + 16] ;ebp = width movq mm5, [edi] mov edx, [esp + 8 + 16] ;ebx = srcs mov eax, [edx+0] mov ebx, [edx+4] add eax, ebp add ebx, ebp neg ebp yloop: ;eax = row0 ;ebx = row1 ;ecx = ;edx = ;edi = kernel ;esi = dest ;ebp = width counter movd mm0, [eax+ebp] punpcklbw mm0, mm7 movd mm2, [ebx+ebp] punpcklbw mm2, mm7 movq mm1, mm0 punpcklwd mm0, mm2 punpckhwd mm1, mm2 pmaddwd mm0, mm5 pmaddwd mm1, mm5 paddd mm0, mm6 paddd mm1, mm6 psrad mm0, 14 psrad mm1, 14 packssdw mm0, mm1 packuswb mm0, mm0 movd [esi], mm0 add esi, 4 add ebp, 4 jne yloop pop ebx pop esi pop edi pop ebp ret } } void __declspec(naked) vdasm_resize_table_col_8_k4_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel) { static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; __asm { push ebp push edi push esi push ebx pxor mm7, mm7 movq mm6, kRound mov esi, [esp + 4 + 16] ;esi = dst mov edi, [esp + 16 + 16] ;edi = kernel xor ebp, ebp mov edx, [esp + 8 + 16] ;ebx = srcs mov eax, [edx+0] mov ebx, [edx+4] mov ecx, [edx+8] mov edx, [edx+12] yloop: ;eax = row0 ;ebx = row1 ;ecx = row2 ;edx = row3 ;edi = kernel ;esi = dest ;ebp = width counter movd mm0, [eax+ebp] punpcklbw mm0, mm7 movd mm2, [ebx+ebp] punpcklbw mm2, mm7 movq mm1, mm0 punpcklwd mm0, mm2 movq mm5, [edi] punpckhwd mm1, mm2 pmaddwd mm0, mm5 pmaddwd mm1, mm5 paddd mm0, mm6 paddd mm1, mm6 movd mm3, [ecx+ebp] punpcklbw mm3, mm7 movd mm2, [edx+ebp] punpcklbw mm2, mm7 movq mm4, mm3 punpcklwd mm3, mm2 movq mm5, [edi+8] punpckhwd mm4, mm2 pmaddwd mm3, mm5 pmaddwd mm4, mm5 paddd mm0, mm3 paddd mm1, mm4 psrad mm0, 14 psrad mm1, 14 packssdw mm0, mm1 packuswb mm0, mm0 add ebp, 4 movd [esi], mm0 add esi, 4 cmp ebp, [esp + 12 + 16] jb yloop pop ebx pop esi pop edi pop ebp ret } } void __declspec(naked) vdasm_resize_table_col_8_MMX(void *dst, const void *const *srcs, uint32 width, const void *kernel, uint32 kwidth) { static const __declspec(align(8)) __int64 kRound = 0x0000200000002000; __asm { push ebp push edi push esi push ebx pxor mm7, mm7 movq mm6, kRound mov edi, [esp + 4 + 16] ;edi = dst xor ebp, ebp yloop: mov edx, [esp + 16 + 16] ;edx = kernel mov ebx, [esp + 8 + 16] ;ebx = srcs mov esi, [esp + 20 + 16] ;esi = kwidth movq mm3, mm6 movq mm4, mm6 xloop: mov ecx, [ebx] movd mm0, [ecx+ebp] punpcklbw mm0, mm7 mov ecx, [ebx+4] movd mm2, [ecx+ebp] punpcklbw mm2, mm7 movq mm1, mm0 punpcklwd mm0, mm2 punpckhwd mm1, mm2 movq mm5, [edx] pmaddwd mm0, mm5 pmaddwd mm1, mm5 paddd mm3, mm0 paddd mm4, mm1 add ebx, 8 add edx, 8 sub esi, 2 jne xloop psrad mm3, 14 psrad mm4, 14 packssdw mm3, mm4 packuswb mm3, mm3 movd [edi], mm3 add edi, 4 add ebp, 4 cmp ebp, [esp + 12 + 16] jb yloop pop ebx pop esi pop edi pop ebp ret } } void VDResamplerSeparableTableColStage8MMX::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { uint8 *dst = (uint8 *)dst0; const uint8 *const *src = (const uint8 *const *)src0; const unsigned ksize = (unsigned)mFilterBank.size() >> 8; const sint16 *filter = (const sint16 *)&mFilterBank[((phase>>8)&0xff) * ksize]; int w4 = w & ~3; if (w4) { switch(ksize) { case 2: vdasm_resize_table_col_8_k2_MMX(dst, (const void *const *)src, w4, filter); break; case 4: vdasm_resize_table_col_8_k4_MMX(dst, (const void *const *)src, w4, filter); break; default: vdasm_resize_table_col_8_MMX(dst, (const void *const *)src, w4, filter, ksize); break; } } for(uint32 i=w4; i>= 14; if ((uint32)b >= 0x00000100) b = ~b >> 31; dst[i] = (uint8)b; } } /////////////////////////////////////////////////////////////////////////// VDResamplerSeparableTableColStageMMX::VDResamplerSeparableTableColStageMMX(const IVDResamplerFilter& filter) : VDResamplerColStageSeparableTable32(filter) { VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); } void VDResamplerSeparableTableColStageMMX::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { vdasm_resize_table_col_MMX((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, (phase >> 8) & 0xff); } /////////////////////////////////////////////////////////////////////////// // // resampler stages (SSE2, x86) // /////////////////////////////////////////////////////////////////////////// extern "C" long vdasm_resize_table_col_SSE2(uint32 *out, const uint32 *const*in_table, const int *filter, int filter_width, uint32 w, long frac); extern "C" long vdasm_resize_table_row_SSE2(uint32 *out, const uint32 *in, const int *filter, int filter_width, uint32 w, long accum, long frac); extern "C" void vdasm_resize_ccint_col_SSE2(void *dst, const void *src1, const void *src2, const void *src3, const void *src4, uint32 count, const void *tbl); VDResamplerSeparableCubicColStageSSE2::VDResamplerSeparableCubicColStageSSE2(double A) : VDResamplerSeparableCubicColStageMMX(A) { } void VDResamplerSeparableCubicColStageSSE2::Process(void *dst0, const void *const *srcarray, uint32 w, sint32 phase) { vdasm_resize_ccint_col_SSE2(dst0, srcarray[0], srcarray[1], srcarray[2], srcarray[3], w, mFilterBank.data() + ((phase>>6)&0x3fc)); } VDResamplerSeparableTableRowStageSSE2::VDResamplerSeparableTableRowStageSSE2(const IVDResamplerFilter& filter) : VDResamplerSeparableTableRowStageMMX(filter) { } void VDResamplerSeparableTableRowStageSSE2::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); } VDResamplerSeparableTableColStageSSE2::VDResamplerSeparableTableColStageSSE2(const IVDResamplerFilter& filter) : VDResamplerSeparableTableColStageMMX(filter) { } void VDResamplerSeparableTableColStageSSE2::Process(void *dst, const void *const *src, uint32 w, sint32 phase) { vdasm_resize_table_col_SSE2((uint32*)dst, (const uint32 *const *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, (phase >> 8) & 0xff); } /////////////////////////////////////////////////////////////////////////// // // resampler stages (SSE4.1, x86) // /////////////////////////////////////////////////////////////////////////// VDResamplerSeparableTableRowStage8SSE41::VDResamplerSeparableTableRowStage8SSE41(const IVDResamplerFilter& filter) : VDResamplerRowStageSeparableTable32(filter) , mLastSrcWidth(0) , mLastDstWidth(0) , mLastU(0) , mLastDUDX(0) { mAlignedKernelWidth = (GetWindowSize() + 15) & ~7; mAlignedKernelSize = mAlignedKernelWidth + 16; } void VDResamplerSeparableTableRowStage8SSE41::Init(const VDResamplerAxis& axis, uint32 srcw) { uint32 w = axis.dx_preclip + axis.dx_active + axis.dx_postclip + axis.dx_dualclip; if (mLastSrcWidth != srcw || mLastDstWidth != w || mLastU != axis.u || mLastDUDX != axis.dudx) { mLastSrcWidth = srcw; mLastDstWidth = w; mLastU = axis.u; mLastDUDX = axis.dudx; RedoRowFilters(axis, w, srcw); } } void VDResamplerSeparableTableRowStage8SSE41::RedoRowFilters(const VDResamplerAxis& axis, uint32 w, uint32 srcw) { int kstride = mFilterBank.size() >> 8; int ksize = mAlignedKernelWidth; int kesize = mAlignedKernelSize; mRowKernels.clear(); mRowKernelSize = w * kesize; mRowKernels.resize(mRowKernelSize * 8, 0); for(int byteOffset = 0; byteOffset < 8; ++byteOffset) { sint16 *dst = mRowKernels.data() + mRowKernelSize * byteOffset; int ksizeThisOffset = std::min(ksize, (byteOffset + srcw + 7) & ~7); mKernelSizeByOffset[byteOffset] = ksizeThisOffset; sint32 u = axis.u; sint32 uoffmin = -byteOffset; sint32 uoffmax = ((srcw + byteOffset + 7) & ~7) - byteOffset - ksizeThisOffset; for(uint32 i=0; i> 16; sint32 uoffset2 = ((uoffset + byteOffset) & ~7) - byteOffset; if (uoffset2 < uoffmin) uoffset2 = uoffmin; if (uoffset2 > uoffmax) uoffset2 = uoffmax; *(sint32 *)dst = uoffset2; dst += 2; *dst++ = 0; *dst++ = 0; *dst++ = 0; *dst++ = 0; *dst++ = 0; *dst++ = 0; uint32 phase = (u >> 8) & 255; const sint32 *src = &mFilterBank[kstride * phase]; sint32 start = 0; sint32 end = kstride; int dstoffset = uoffset - uoffset2; // check for filter kernel overlapping left source boundary if (uoffset < 0) start = -uoffset; // check for filter kernel overlapping right source boundary if (uoffset + end > (sint32)srcw) end = srcw - uoffset; VDASSERT(dstoffset + start >= 0); VDASSERT(dstoffset + end <= ksizeThisOffset); sint16 *dst2 = dst + dstoffset; dst += ksizeThisOffset; for(int j=start; j 0) dst2[start] = std::accumulate(src, src+start, dst2[start]); if (end < kstride) dst2[end - 1] = std::accumulate(src+end, src+kstride, dst2[end - 1]); u += axis.dudx; } } // swizzle rows where optimization is possible vdfastvector temp; int quads = w >> 2; int quadRemainder = w & 3; for(int byteOffset = 0; byteOffset < 8; ++byteOffset) { int ksizeThisOffset = mKernelSizeByOffset[byteOffset]; int kpairs = ksizeThisOffset >> 3; if (ksizeThisOffset < 8 || ksizeThisOffset > 16) { mbQuadOptimizationEnabled[byteOffset] = false; } else { ptrdiff_t unswizzledStride = (ksizeThisOffset >> 1) + 4; mbQuadOptimizationEnabled[byteOffset] = true; mTailOffset[byteOffset] = quads * (8 + ksizeThisOffset*4); uint32 *dst = (uint32 *)&mRowKernels[mRowKernelSize * byteOffset]; temp.resize(mRowKernelSize); memcpy(temp.data(), dst, mRowKernelSize*2); const uint32 *src0 = (const uint32 *)temp.data(); const uint32 *src1 = src0 + unswizzledStride; const uint32 *src2 = src1 + unswizzledStride; const uint32 *src3 = src2 + unswizzledStride; ptrdiff_t srcskip = unswizzledStride * 3; for(int q = 0; q < quads; ++q) { dst[0] = src0[0]; dst[1] = src1[0]; dst[2] = src2[0]; dst[3] = src3[0]; src0 += 4; src1 += 4; src2 += 4; src3 += 4; dst += 4; for(int p = 0; p < kpairs; ++p) { dst[ 0] = src0[0]; dst[ 1] = src0[1]; dst[ 2] = src0[2]; dst[ 3] = src0[3]; dst[ 4] = src1[0]; dst[ 5] = src1[1]; dst[ 6] = src1[2]; dst[ 7] = src1[3]; dst[ 8] = src2[0]; dst[ 9] = src2[1]; dst[10] = src2[2]; dst[11] = src2[3]; dst[12] = src3[0]; dst[13] = src3[1]; dst[14] = src3[2]; dst[15] = src3[3]; dst += 16; src0 += 4; src1 += 4; src2 += 4; src3 += 4; } src0 += srcskip; src1 += srcskip; src2 += srcskip; src3 += srcskip; } memcpy(dst, src0, unswizzledStride * 4 * quadRemainder); } } } void VDResamplerSeparableTableRowStage8SSE41::Process(void *dst, const void *src, uint32 w) { int byteOffset = (int)(ptrdiff_t)src & 7; const sint16 *ksrc = mRowKernels.data() + (mRowKernelSize * byteOffset); int ksize = mKernelSizeByOffset[byteOffset]; if (mbQuadOptimizationEnabled[byteOffset]) { if (w >= 4) { if (ksize == 16) vdasm_resize_table_row_8_k16_4x_SSE41(dst, src, w >> 2, ksrc); else vdasm_resize_table_row_8_k8_4x_SSE41(dst, src, w >> 2, ksrc); } if (w & 3) vdasm_resize_table_row_8_SSE41((char *)dst + (w & ~3), src, w & 3, ksrc + mTailOffset[byteOffset], ksize); } else if (w) { vdasm_resize_table_row_8_SSE41(dst, src, w, ksrc, ksize); } } void VDResamplerSeparableTableRowStage8SSE41::Process(void *dst, const void *src, uint32 w, uint32 u, uint32 dudx) { vdasm_resize_table_row_MMX((uint32 *)dst, (const uint32 *)src, (const int *)mFilterBank.data(), (int)mFilterBank.size() >> 8, w, u, dudx); } /////////////////////////////////////////////////////////////////////////// VDResamplerSeparableTableColStage8SSE41::VDResamplerSeparableTableColStage8SSE41(const IVDResamplerFilter& filter) : VDResamplerColStageSeparableTable8(filter) { VDResamplerSwizzleTable(mFilterBank.data(), (unsigned)mFilterBank.size() >> 1); } void VDResamplerSeparableTableColStage8SSE41::Process(void *dst0, const void *const *src0, uint32 w, sint32 phase) { uint8 *dst = (uint8 *)dst0; const uint8 *const *src = (const uint8 *const *)src0; const unsigned ksize = (unsigned)mFilterBank.size() >> 8; const sint16 *filter = (const sint16 *)&mFilterBank[((phase>>8)&0xff) * ksize]; int w4 = w & ~3; if (w4) { switch(ksize) { case 2: vdasm_resize_table_col_8_k2_SSE41(dst, (const void *const *)src, w4, filter); break; case 4: vdasm_resize_table_col_8_k4_SSE41(dst, (const void *const *)src, w4, filter); break; default: vdasm_resize_table_col_8_MMX(dst, (const void *const *)src, w4, filter, ksize); break; } } for(uint32 i=w4; i>= 14; if ((uint32)b >= 0x00000100) b = ~b >> 31; dst[i] = (uint8)b; } }