JD2022-TU1/main/extern/libvpx/custom/vp8/common/durango/subpixel_durango.cpp

1003 lines
37 KiB
C++

/*
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "vpx_config.h"
#if defined(DURANGO)
#include "vp8/common/optimisation_vecops.h"
#include "vp8/common/optimisation_profiling.h"
#include <assert.h>
#define DEBUG_OPTIMISED_FILTERS 0
#if DEBUG_OPTIMISED_FILTERS
#include <stdio.h>
#endif //DEBUG_OPTIMISED_FILTERS
#define UNROLL_16X16_HORIZ 1
#define UNROLL_8X8_HORIZ 1
#define UNROLL_4X4_HORIZ 1
//////////////////////////////////////////////////////////////////////////
extern "C" const short vp8_sub_pel_filters[8][6];
__declspec(align(16)) short subpixel_Filter[] =
{
0, 0,128, 0, 0, 0, 0, 0,
0, -6,123, 12, -1, 0, 0, 0,
2,-11,108, 36, -8, 1, 0, 0,
0, -9, 93, 50, -6, 0, 0, 0,
3,-16, 77, 77,-16, 3, 0, 0,
0, -6, 50, 93, -9, 0, 0, 0,
1, -8, 36,108,-11, 2, 0, 0,
0, -1, 12,123, -6, 0, 0, 0
};
//////////////////////////////////////////////////////////////////////////
__forceinline void CachePrefetch4Start(const void* pAddr, int pitch)
{
CacheTouch(pAddr, 0);
CacheTouch(pAddr, pitch);
CacheTouch(pAddr, 2*pitch);
CacheTouch(pAddr, 3*pitch);
}
__forceinline void CachePrefetch4Next(const void* pAddr, int pitch)
{
CacheTouch(pAddr, 4*pitch);
}
__forceinline void CachePrefetch6Start(const void* pAddr, int pitch)
{
CacheTouch(pAddr, 0);
CacheTouch(pAddr, pitch);
CacheTouch(pAddr, 2*pitch);
CacheTouch(pAddr, 3*pitch);
CacheTouch(pAddr, 4*pitch);
CacheTouch(pAddr, 5*pitch);
}
__forceinline void CachePrefetch6Next(const void* pAddr, int pitch)
{
CacheTouch(pAddr, 6*pitch);
}
// Functions for FP-mul implementation of filter kernel
__forceinline v128f_t GenerateFilterScaleF32() { return VecConvertI32ToF32WithExponentShiftRight< 7>(VecSplatImmediateWord<1>()); }
__forceinline v128f_t GenerateSmallValue() { return VecConvertI32ToF32WithExponentShiftRight<13>(VecSplatImmediateWord<1>()); }
__forceinline v128f_t GenerateMinValue() { return VecSplatImmediateFloat< 0>(); }
__forceinline v128f_t GenerateMaxValue() { return VecSplatImmediateFloat<255>(); }
__forceinline void sixtap_fp_horiz_InitialiseFilterKernel(
v128f_t& vFilterScale,
v128f_t& vSmallValue,
v128f_t& vMinValue,
v128f_t& vMaxValue)
{
vFilterScale = GenerateFilterScaleF32();
vMinValue = GenerateMinValue();
vMaxValue = GenerateMaxValue();
vSmallValue = GenerateSmallValue();
}
__forceinline void sixtap_fp_vert_InitialiseFilterKernel(
v128f_t& vFilterScale,
v128f_t& vSmallValue)
{
vFilterScale = GenerateFilterScaleF32();
vSmallValue = GenerateSmallValue();
}
__forceinline void Load8SignedShortsAlignedAndConvertToFloat(const short* __restrict pSrc, int iOffset, v128f_t* __restrict pvDest)
{
v128i_t vTemp[2];
vTemp[0] = VecLoadAlignedI32(pSrc, iOffset);
vTemp[1] = VecUnpackHiSignedHalf(vTemp[0]);
vTemp[0] = VecUnpackLoSignedHalf(vTemp[0]);
pvDest[1] = VecConvertI32ToF32(vTemp[1]);
pvDest[0] = VecConvertI32ToF32(vTemp[0]);
}
template <int count>
__forceinline void UnpackU8sToF32s(v128f_t* __restrict vOut, const v128i_t vIn)
{
assert((count & 3) == 0); // only valid for a multiple of 4
assert(count <= 16); // use multiple calls for counts greater than 16
assert(0); // this is a reference implementation - not to be used!
for (int i=0; i<count; ++i)
{
vOut[i>>2] = VecOpsInternal::VecInsertF32(vOut[i>>2], (float)VecOpsInternal::VecExtractU8(vIn, i), i&3);
}
}
template <>
__forceinline void UnpackU8sToF32s<16>(v128f_t* __restrict vOut, const v128i_t vIn)
{
v128i_t vUnpackTemp[4];
vUnpackTemp[1] = VecUnpackLoUnsignedByte(vIn);
vUnpackTemp[3] = VecUnpackHiUnsignedByte(vIn);
vUnpackTemp[0] = VecUnpackLoSignedHalf(vUnpackTemp[1]);
vUnpackTemp[1] = VecUnpackHiSignedHalf(vUnpackTemp[1]);
vUnpackTemp[2] = VecUnpackLoSignedHalf(vUnpackTemp[3]);
vUnpackTemp[3] = VecUnpackHiSignedHalf(vUnpackTemp[3]);
vOut[0] = VecConvertI32ToF32(vUnpackTemp[0]);
vOut[1] = VecConvertI32ToF32(vUnpackTemp[1]);
vOut[2] = VecConvertI32ToF32(vUnpackTemp[2]);
vOut[3] = VecConvertI32ToF32(vUnpackTemp[3]);
}
template <>
__forceinline void UnpackU8sToF32s<12>(v128f_t* __restrict vOut, const v128i_t vIn)
{
v128i_t vUnpackTemp[3];
vUnpackTemp[1] = VecUnpackLoUnsignedByte(vIn);
vUnpackTemp[2] = VecUnpackHiUnsignedByte(vIn);
vUnpackTemp[0] = VecUnpackLoSignedHalf(vUnpackTemp[1]);
vUnpackTemp[1] = VecUnpackHiSignedHalf(vUnpackTemp[1]);
vUnpackTemp[2] = VecUnpackLoSignedHalf(vUnpackTemp[2]);
vOut[0] = VecConvertI32ToF32(vUnpackTemp[0]);
vOut[1] = VecConvertI32ToF32(vUnpackTemp[1]);
vOut[2] = VecConvertI32ToF32(vUnpackTemp[2]);
}
template <>
__forceinline void UnpackU8sToF32s<8>(v128f_t* __restrict vOut, const v128i_t vIn)
{
v128i_t vUnpackTemp[2];
vUnpackTemp[1] = VecUnpackLoUnsignedByte(vIn);
vUnpackTemp[0] = VecUnpackLoSignedHalf(vUnpackTemp[1]);
vUnpackTemp[1] = VecUnpackHiSignedHalf(vUnpackTemp[1]);
vOut[0] = VecConvertI32ToF32(vUnpackTemp[0]);
vOut[1] = VecConvertI32ToF32(vUnpackTemp[1]);
}
template <>
__forceinline void UnpackU8sToF32s<4>(v128f_t* __restrict vOut, const v128i_t vIn)
{
v128i_t vUnpackTemp;
vUnpackTemp = VecUnpackLoUnsignedByte(vIn);
vUnpackTemp = VecUnpackLoSignedHalf(vUnpackTemp);
vOut[0] = VecConvertI32ToF32(vUnpackTemp);
}
__forceinline void Transpose4FloatVecs(v128f_t* __restrict vVals)
{
v128f_t vTemp[4];
vTemp[0] = VecInterleaveLoFloat(vVals[0], vVals[2]);
vTemp[1] = VecInterleaveHiFloat(vVals[0], vVals[2]);
vTemp[2] = VecInterleaveLoFloat(vVals[1], vVals[3]);
vTemp[3] = VecInterleaveHiFloat(vVals[1], vVals[3]);
vVals[0] = VecInterleaveLoFloat(vTemp[0], vTemp[2]);
vVals[1] = VecInterleaveHiFloat(vTemp[0], vTemp[2]);
vVals[2] = VecInterleaveLoFloat(vTemp[1], vTemp[3]);
vVals[3] = VecInterleaveHiFloat(vTemp[1], vTemp[3]);
}
__forceinline v128f_t sixtap_fp_FilterKernelAndAdvance(v128f_t& vIn0, v128f_t& vIn1, v128f_t& vIn2, v128f_t& vFilter0, v128f_t& vFilter1)
{
v128f_t vRes0, vRes1, vRes;
vRes0 = VecDP4Float(vIn0, vFilter0);
vRes1 = VecDP4Float(vIn1, vFilter1);
vRes = VecAddFloat(vRes0, vRes1);
vIn0 = VecPermuteFloat<1,2,3,4>(vIn0, vIn1);
vIn1 = VecPermuteFloat<1,2,3,4>(vIn1, vIn2);
vIn2 = VecShuffleFloat<1,2,3,0>(vIn2);
return vRes;
}
__forceinline v128f_t sixtap_fp_FilterKernelMerge(v128f_t* __restrict vIn)
{
v128f_t v1, v2;
v1 = VecInterleaveLoFloat(vIn[0], vIn[2]);
v2 = VecInterleaveLoFloat(vIn[1], vIn[3]);
return VecInterleaveLoFloat(v1, v2);
}
__forceinline v128f_t sixtap_fp_FilterClamp(v128f_t vIn, v128f_t vMin, v128f_t vMax, v128f_t vSmall)
{
vIn = VecMinFloat(vIn, vMax);
vIn = VecMaxFloat(vIn, vMin);
vIn = VecAddFloat(vIn, vSmall);
return VecRoundFloatNearest(vIn);
}
__forceinline v128i_t sixtap_fp_FilterConvert(v128f_t vIn, v128f_t vSmall)
{
v128i_t vRes;
vIn = VecAddFloat(vIn, vSmall);
vIn = VecRoundFloatNearest(vIn);
vRes = VecConvertF32ToI32(vIn);
vRes = VecPackSignedWordToSignedHalfSaturate(vRes, vRes);
return VecPackSignedHalfToUnsignedByteSaturate(vRes, vRes);
}
//////////////////////////////////////////////////////////////////////////
template <int k_Cols>
__forceinline static void sixtap_fp_LoadAndUnpackFilterInputValues(unsigned char* p_Src, v128f_t* pv_Dest)
{
assert(0); // Not implemented
}
template <>
__forceinline static void sixtap_fp_LoadAndUnpackFilterInputValues<16>(unsigned char* p_Src, v128f_t* pv_Dest)
{
v128i_t v_Bytes[2];
v_Bytes[0] = VecLoadUnalignedI32(p_Src, 0);
v_Bytes[1] = VecLoadUnalignedI32(p_Src, 16);
UnpackU8sToF32s<16>(&pv_Dest[0], v_Bytes[0]);
UnpackU8sToF32s< 8>(&pv_Dest[4], v_Bytes[1]);
}
template <>
__forceinline static void sixtap_fp_LoadAndUnpackFilterInputValues<8>(unsigned char* p_Src, v128f_t* pv_Dest)
{
v128i_t v_Line;
v_Line = VecLoadUnalignedI32(p_Src, 0);
UnpackU8sToF32s<16>(pv_Dest, v_Line);
}
template <>
__forceinline static void sixtap_fp_LoadAndUnpackFilterInputValues<4>(unsigned char* p_Src, v128f_t* pv_Dest)
{
v128i_t v_Line;
v_Line = VecLoadUnalignedI32(p_Src, 0);
UnpackU8sToF32s<12>(pv_Dest, v_Line);
}
//////////////////////////////////////////////////////////////////////////
template <int k_Cols>
__forceinline static void sixtap_fp_horiz_PassthroughValues(unsigned char* src, v128f_t* pv_Dest)
{
assert(0); // Not implemented
}
template <>
__forceinline static void sixtap_fp_horiz_PassthroughValues<16>(unsigned char* p_Src, v128f_t* pv_Dest)
{
v128i_t v_Bytes = VecLoadUnalignedI32(p_Src, 0);
v128f_t v_FloatBuffer[4];
UnpackU8sToF32s<16>(v_FloatBuffer, v_Bytes);
assert(((unsigned long)pv_Dest & 0xf) == 0);
VecStoreUnalignedF32(v_FloatBuffer[0], pv_Dest, 0 );
VecStoreUnalignedF32(v_FloatBuffer[1], pv_Dest, 16);
VecStoreUnalignedF32(v_FloatBuffer[2], pv_Dest, 32);
VecStoreUnalignedF32(v_FloatBuffer[3], pv_Dest, 48);
}
template <>
__forceinline static void sixtap_fp_horiz_PassthroughValues<8>(unsigned char* p_Src, v128f_t* pv_Dest)
{
v128i_t v_Bytes = VecLoadUnalignedI32(p_Src, 0);
v128f_t v_FloatBuffer[2];
UnpackU8sToF32s<8>(v_FloatBuffer, v_Bytes);
assert(((unsigned long)pv_Dest & 0xf) == 0);
VecStoreUnalignedF32(v_FloatBuffer[0], pv_Dest, 0 );
VecStoreUnalignedF32(v_FloatBuffer[1], pv_Dest, 16);
}
template <>
__forceinline static void sixtap_fp_horiz_PassthroughValues<4>(unsigned char* p_Src, v128f_t* pv_Dest)
{
v128i_t v_Bytes = VecLoadUnalignedI32(p_Src, 0);
v128f_t v_FloatBuffer;
UnpackU8sToF32s<4>(&v_FloatBuffer, v_Bytes);
assert(((unsigned long)pv_Dest & 0xf) == 0);
VecStoreUnalignedF32(v_FloatBuffer, pv_Dest, 0 );
}
//////////////////////////////////////////////////////////////////////////
template <int k_Cols>
__forceinline static void sixtap_fp_vert_PassthroughValues(v128f_t* pv_Src, unsigned char* p_Dest)
{
assert(0); // Not implemented
}
template <>
__forceinline static void sixtap_fp_vert_PassthroughValues<16>(v128f_t* pv_Src, unsigned char* p_Dest)
{
v128f_t v_RowF[4];
v128i_t v_RowI[4];
v_RowF[0] = VecLoadAlignedF32(pv_Src, 0);
v_RowF[1] = VecLoadAlignedF32(pv_Src, 16);
v_RowF[2] = VecLoadAlignedF32(pv_Src, 32);
v_RowF[3] = VecLoadAlignedF32(pv_Src, 48);
v_RowI[0] = VecConvertF32ToI32(v_RowF[0]);
v_RowI[1] = VecConvertF32ToI32(v_RowF[1]);
v_RowI[2] = VecConvertF32ToI32(v_RowF[2]);
v_RowI[3] = VecConvertF32ToI32(v_RowF[3]);
v_RowI[0] = VecPackSignedWordToSignedHalfSaturate(v_RowI[0], v_RowI[1]);
v_RowI[2] = VecPackSignedWordToSignedHalfSaturate(v_RowI[2], v_RowI[3]);
v_RowI[0] = VecPackSignedHalfToUnsignedByteSaturate(v_RowI[0], v_RowI[2]);
assert(((unsigned long)p_Dest & 0xf) == 0); // must be 16 byte aligned to use stvx
VecStoreAlignedI32(v_RowI[0], p_Dest, 0);
}
template <>
__forceinline static void sixtap_fp_vert_PassthroughValues<8>(v128f_t* pv_Src, unsigned char* p_Dest)
{
v128i_t v_CurrentRow;
v_CurrentRow = VecLoadUnalignedI32(p_Dest, 0);
v128f_t v_RowF[2];
v128i_t v_RowI[2];
v_RowF[0] = VecLoadAlignedF32(pv_Src, 0);
v_RowF[1] = VecLoadAlignedF32(pv_Src, 16);
v_RowI[0] = VecConvertF32ToI32(v_RowF[0]);
v_RowI[1] = VecConvertF32ToI32(v_RowF[1]);
v_RowI[0] = VecPackSignedWordToSignedHalfSaturate(v_RowI[0], v_RowI[1]);
v_RowI[0] = VecPackSignedHalfToUnsignedByteSaturate(v_RowI[0], v_RowI[0]);
v_CurrentRow = VecPermuteWord<0,1,6,7>(v_RowI[0], v_CurrentRow);
VecStoreUnalignedI32(v_CurrentRow, p_Dest, 0);
}
template <>
__forceinline static void sixtap_fp_vert_PassthroughValues<4>(v128f_t* pv_Src, unsigned char* p_Dest)
{
v128i_t v_CurrentRow;
v_CurrentRow = VecLoadUnalignedI32(p_Dest, 0);
v128f_t v_RowF;
v128i_t v_RowI;
v_RowF = VecLoadAlignedF32(pv_Src, 0);
v_RowI = VecConvertF32ToI32(v_RowF);
v_RowI = VecPackSignedWordToSignedHalfSaturate(v_RowI, v_RowI);
v_RowI = VecPackSignedHalfToUnsignedByteSaturate(v_RowI, v_RowI);
v_CurrentRow = VecPermuteWord<0,5,6,7>(v_RowI, v_CurrentRow);
VecStoreUnalignedI32(v_CurrentRow, p_Dest, 0);
}
//////////////////////////////////////////////////////////////////////////
template <int k_Cols>
__forceinline static void sixtap_fp_horiz_PerformFilterKernel(
v128f_t* pv_Dest
, v128f_t* pv_Input
, v128f_t* pv_Results
, v128f_t* pv_HFilter
, v128f_t v_Min
, v128f_t v_Max
, v128f_t v_SmallAmount
#if DEBUG_OPTIMISED_FILTERS
, int* debug_src
#endif
)
{
for (int i_ColGrp=0; i_ColGrp<(k_Cols/4); ++i_ColGrp)
{
for (int i_Col=0; i_Col<4; ++i_Col)
{
pv_Results[i_Col] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2+i_ColGrp], pv_HFilter[0], pv_HFilter[1]);
}
pv_Results[0] = sixtap_fp_FilterKernelMerge(pv_Results);
pv_Results[0] = sixtap_fp_FilterClamp(pv_Results[0], v_Min, v_Max, v_SmallAmount);
assert(((unsigned long)pv_Dest & 0xf) == 0);
VecStoreAlignedF32(pv_Results[0], pv_Dest, 0);
#if DEBUG_OPTIMISED_FILTERS
for (unsigned int ui_Debug_Col=0; ui_Debug_Col<4; ++ui_Debug_Col)
{
if ((int)VecOpsInternal::VecExtractF32(*pv_Dest, ui_Debug_Col) != *debug_src )
{
printf("Bad stuff in HFilter. %d off\n", (int)VecOpsInternal::VecExtractF32(*pv_Dest, ui_Debug_Col) - *debug_src);
}
debug_src++;
}
#endif
pv_Dest++; // move to the next element
}
}
#if UNROLL_16X16_HORIZ && (DEBUG_OPTIMISED_FILTERS == 0)
template <>
__forceinline static void sixtap_fp_horiz_PerformFilterKernel<16>(
v128f_t* pv_Dest
, v128f_t* pv_Input
, v128f_t* pv_Results
, v128f_t* pv_HFilter
, v128f_t v_Min
, v128f_t v_Max
, v128f_t v_SmallAmount
)
{
pv_Results[0] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2], pv_HFilter[0], pv_HFilter[1]);
pv_Results[1] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2], pv_HFilter[0], pv_HFilter[1]);
pv_Results[2] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2], pv_HFilter[0], pv_HFilter[1]);
pv_Results[3] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2], pv_HFilter[0], pv_HFilter[1]);
pv_Results[0] = sixtap_fp_FilterKernelMerge(pv_Results);
pv_Results[0] = sixtap_fp_FilterClamp(pv_Results[0], v_Min, v_Max, v_SmallAmount);
VecStoreAlignedF32(pv_Results[0], pv_Dest++, 0);
pv_Results[0] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[3], pv_HFilter[0], pv_HFilter[1]);
pv_Results[1] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[3], pv_HFilter[0], pv_HFilter[1]);
pv_Results[2] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[3], pv_HFilter[0], pv_HFilter[1]);
pv_Results[3] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[3], pv_HFilter[0], pv_HFilter[1]);
pv_Results[0] = sixtap_fp_FilterKernelMerge(pv_Results);
pv_Results[0] = sixtap_fp_FilterClamp(pv_Results[0], v_Min, v_Max, v_SmallAmount);
VecStoreAlignedF32(pv_Results[0], pv_Dest++, 0);
pv_Results[0] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[4], pv_HFilter[0], pv_HFilter[1]);
pv_Results[1] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[4], pv_HFilter[0], pv_HFilter[1]);
pv_Results[2] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[4], pv_HFilter[0], pv_HFilter[1]);
pv_Results[3] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[4], pv_HFilter[0], pv_HFilter[1]);
pv_Results[0] = sixtap_fp_FilterKernelMerge(pv_Results);
pv_Results[0] = sixtap_fp_FilterClamp(pv_Results[0], v_Min, v_Max, v_SmallAmount);
VecStoreAlignedF32(pv_Results[0], pv_Dest++, 0);
pv_Results[0] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[5], pv_HFilter[0], pv_HFilter[1]);
pv_Results[1] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[5], pv_HFilter[0], pv_HFilter[1]);
pv_Results[2] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[5], pv_HFilter[0], pv_HFilter[1]);
pv_Results[3] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[5], pv_HFilter[0], pv_HFilter[1]);
pv_Results[0] = sixtap_fp_FilterKernelMerge(pv_Results);
pv_Results[0] = sixtap_fp_FilterClamp(pv_Results[0], v_Min, v_Max, v_SmallAmount);
VecStoreAlignedF32(pv_Results[0], pv_Dest++, 0);
}
#endif
#if UNROLL_8X8_HORIZ && (DEBUG_OPTIMISED_FILTERS == 0)
template <>
__forceinline static void sixtap_fp_horiz_PerformFilterKernel<8>(
v128f_t* pv_Dest
, v128f_t* pv_Input
, v128f_t* pv_Results
, v128f_t* pv_HFilter
, v128f_t v_Min
, v128f_t v_Max
, v128f_t v_SmallAmount
)
{
pv_Results[0] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2], pv_HFilter[0], pv_HFilter[1]);
pv_Results[1] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2], pv_HFilter[0], pv_HFilter[1]);
pv_Results[2] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2], pv_HFilter[0], pv_HFilter[1]);
pv_Results[3] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2], pv_HFilter[0], pv_HFilter[1]);
pv_Results[0] = sixtap_fp_FilterKernelMerge(pv_Results);
pv_Results[0] = sixtap_fp_FilterClamp(pv_Results[0], v_Min, v_Max, v_SmallAmount);
VecStoreAlignedF32(pv_Results[0], pv_Dest++, 0);
pv_Results[0] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[3], pv_HFilter[0], pv_HFilter[1]);
pv_Results[1] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[3], pv_HFilter[0], pv_HFilter[1]);
pv_Results[2] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[3], pv_HFilter[0], pv_HFilter[1]);
pv_Results[3] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[3], pv_HFilter[0], pv_HFilter[1]);
pv_Results[0] = sixtap_fp_FilterKernelMerge(pv_Results);
pv_Results[0] = sixtap_fp_FilterClamp(pv_Results[0], v_Min, v_Max, v_SmallAmount);
VecStoreAlignedF32(pv_Results[0], pv_Dest++, 0);
}
#endif
#if UNROLL_4X4_HORIZ && (DEBUG_OPTIMISED_FILTERS == 0)
template <>
__forceinline static void sixtap_fp_horiz_PerformFilterKernel<4>(
v128f_t* pv_Dest
, v128f_t* pv_Input
, v128f_t* pv_Results
, v128f_t* pv_HFilter
, v128f_t v_Min
, v128f_t v_Max
, v128f_t v_SmallAmount
)
{
pv_Results[0] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2], pv_HFilter[0], pv_HFilter[1]);
pv_Results[1] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2], pv_HFilter[0], pv_HFilter[1]);
pv_Results[2] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2], pv_HFilter[0], pv_HFilter[1]);
pv_Results[3] = sixtap_fp_FilterKernelAndAdvance(pv_Input[0], pv_Input[1], pv_Input[2], pv_HFilter[0], pv_HFilter[1]);
pv_Results[0] = sixtap_fp_FilterKernelMerge(pv_Results);
pv_Results[0] = sixtap_fp_FilterClamp(pv_Results[0], v_Min, v_Max, v_SmallAmount);
VecStoreAlignedF32(pv_Results[0], pv_Dest++, 0);
}
#endif
//////////////////////////////////////////////////////////////////////////
template <int k_Cols>
__forceinline static void sixtap_fp_horiz_ClearUnusedRows(v128f_t* pv_Dest)
{
assert(0); // Not implemented
}
template <>
__forceinline static void sixtap_fp_horiz_ClearUnusedRows<16>(v128f_t* pv_Dest)
{
v128f_t v_Zero = VecSplatImmediateFloat<0>();
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
}
template <>
__forceinline static void sixtap_fp_horiz_ClearUnusedRows<8>(v128f_t* pv_Dest)
{
v128f_t v_Zero = VecSplatImmediateFloat<0>();
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
}
template <>
__forceinline static void sixtap_fp_horiz_ClearUnusedRows<4>(v128f_t* pv_Dest)
{
v128f_t v_Zero = VecSplatImmediateFloat<0>();
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
VecStoreAlignedF32(v_Zero, pv_Dest++, 0);
}
//////////////////////////////////////////////////////////////////////////
template <int k_Cols>
__forceinline static void sixtap_fp_vert_StoreRowValues(v128i_t v_Values, unsigned char* p_Dest, int ui_ColGrp)
{
// Each 4 byte element is equal as a result of the packing of the results during sixtap_fp_FilterConvert
VecStore4ByteAlignedAnyI32(v_Values, (int*)p_Dest + ui_ColGrp);
}
// template <>
// __forceinline static void sixtap_fp_vert_StoreRowValues<16>(v128i_t v_Values, unsigned char* p_Dest, int ui_ColGrp)
// {
// VecStore4ByteAlignedAnyI32(v_Values, (int*)p_Dest + ui_ColGrp);
// }
//////////////////////////////////////////////////////////////////////////
template <int k_Cols, int k_Rows>
/*__forceinline */static void vp8_sixtap_predict_durango_horiz(
unsigned char* __restrict src
, int src_pitch
, int xofst
, int yofst
, v128f_t* __restrict dst
, int dst_pitch
#if DEBUG_OPTIMISED_FILTERS
, int* debug_src
, unsigned int debug_src_pitch
#endif
)
{
if (xofst)
{
PRF_Scoped("sixtap_horiz<%d,%d> filtered", k_Cols, k_Rows);
v128f_t v_HFilter[2];
Load8SignedShortsAlignedAndConvertToFloat(&subpixel_Filter[xofst << 3], 0, v_HFilter); // multiply offset by 8 as there are 8 filter values per row
unsigned int ui_RowsToFilter;
bool b_ClearPadRows;
v128f_t* p_Dest;
unsigned char* p_Src;
if (yofst == 0)
{
p_Src = src - 2;
p_Dest = (v128f_t*)(((char*)dst) + (dst_pitch * 2));
ui_RowsToFilter = k_Rows;
b_ClearPadRows = false;
#if DEBUG_OPTIMISED_FILTERS
debug_src += debug_src_pitch*2;
#endif
}
else
{
// When yofst is 0 no vertical filtering is performed. Because the vertical pass follows the
// horizontal pass, and additional input data is required for the vertical filtering, the
// additional rows don't need to be filtered in this situation
p_Src = src - (src_pitch * 2) - 2; // expand the source pointer to filter additional rows when a vertical filter pass will also be applied.
p_Dest = dst;
ui_RowsToFilter = k_Rows + 5; // filter <rows>+5 rows
b_ClearPadRows = true;
}
CachePrefetch4Start(p_Src, src_pitch);
v128f_t v_FilterScale;
v128f_t v_Min, v_Max;
v128f_t v_SmallAmount;
sixtap_fp_horiz_InitialiseFilterKernel(
v_FilterScale,
v_SmallAmount,
v_Min,
v_Max);
v_HFilter[0] = VecMulFloat(v_HFilter[0], v_FilterScale);
v_HFilter[1] = VecMulFloat(v_HFilter[1], v_FilterScale);
for (unsigned int ui_Row=0; ui_Row < ui_RowsToFilter; ++ui_Row)
{
//Load a line of <kui_OutputCols+5> bytes into <(kui_OutputCols+5)/4 + 1> vectors
v128f_t v_RowValues[(k_Cols+5)/4 + 1];
sixtap_fp_LoadAndUnpackFilterInputValues<k_Cols>(p_Src, v_RowValues);
v128f_t v_Results[4];
#if DEBUG_OPTIMISED_FILTERS
sixtap_fp_horiz_PerformFilterKernel<k_Cols>(p_Dest, v_RowValues, v_Results, v_HFilter, v_Min, v_Max, v_SmallAmount, debug_src);
debug_src += debug_src_pitch;
#else
sixtap_fp_horiz_PerformFilterKernel<k_Cols>(p_Dest, v_RowValues, v_Results, v_HFilter, v_Min, v_Max, v_SmallAmount);
#endif
CachePrefetch4Next(p_Src, src_pitch);
p_Src += src_pitch;
p_Dest = (v128f_t*)(((char*)p_Dest) + dst_pitch);
}
if (b_ClearPadRows)
{
sixtap_fp_horiz_ClearUnusedRows<k_Cols>(p_Dest);
}
}
else
{
PRF_Scoped("sixtap_horiz<%d,%d> bypassed", k_Cols, k_Rows);
unsigned int ui_RowsToFilter;
bool b_ClearPadRows;
v128f_t* p_Dest;
unsigned char* p_Src;
if (yofst == 0)
{
p_Src = src;
p_Dest = dst;
ui_RowsToFilter = k_Rows;
b_ClearPadRows = false;
#if DEBUG_OPTIMISED_FILTERS
debug_src += debug_src_pitch*2;
#endif
}
else
{
p_Src = src - (src_pitch * 2); // expand the source pointer to filter additional rows when a vertical filter pass will also be applied.
p_Dest = dst;
ui_RowsToFilter = k_Rows + 5;
b_ClearPadRows = true;
}
CachePrefetch6Start(p_Src, src_pitch);
for (unsigned int ui_Row=0; ui_Row < ui_RowsToFilter; ++ui_Row)
{
sixtap_fp_horiz_PassthroughValues<k_Cols>(p_Src, p_Dest);
#if DEBUG_OPTIMISED_FILTERS
for (unsigned int ui_Debug_Col=0; ui_Debug_Col < k_Cols; ++ui_Debug_Col)
{
if ((int)(((float*)p_Dest)[ui_Debug_Col]) != debug_src[ui_Debug_Col] )
{
printf("Bad stuff in HFilter-bypass.\n");
}
}
debug_src += debug_src_pitch;
#endif
p_Dest = (v128f_t*)(((char*)p_Dest) + dst_pitch);
CachePrefetch6Next(p_Src, src_pitch);
p_Src += src_pitch;
}
if (b_ClearPadRows)
{
sixtap_fp_horiz_ClearUnusedRows<k_Cols>(p_Dest);
}
}
}
template <int k_Cols, int k_Rows>
/*__forceinline */static void vp8_sixtap_predict_durango_vert(
v128f_t* __restrict src
, int src_pitch
, int xofst
, int yofst
, unsigned char* __restrict dst
, int dst_pitch
#if DEBUG_OPTIMISED_FILTERS
, unsigned char* debug_src
, int debug_src_pitch
#endif
)
{
if (yofst)
{
PRF_Scoped("sixtap_vert<%d,%d> filtered", k_Cols, k_Rows);
v128f_t v_VFilter[2];
// unpack filter values - source filters are SIGNED shorts (this is important to remember - vector operations won't check that you're using the correct sign)
Load8SignedShortsAlignedAndConvertToFloat(&subpixel_Filter[yofst << 3], 0, v_VFilter); // multiply by 8 as there are 8 filter values per row
v128f_t v_FilterScale, v_SmallAmount;
sixtap_fp_vert_InitialiseFilterKernel(v_FilterScale, v_SmallAmount);
v_VFilter[0] = VecMulFloat(v_VFilter[0], v_FilterScale);
v_VFilter[1] = VecMulFloat(v_VFilter[1], v_FilterScale);
assert((k_Cols&3) == 0);
for (unsigned int ui_ColGrp=0; ui_ColGrp<(k_Cols/4); ++ui_ColGrp)
{
v128f_t* p_Src = src;
unsigned char* p_Dest = dst;
#if DEBUG_OPTIMISED_FILTERS
unsigned char* p_DebugDest = debug_src;
#endif
v128f_t v_SrcData[12];
unsigned int ui_ColDataOffset = ui_ColGrp*16;
assert(((__int64)p_Src & 0xf) == 0);
// Begin by loading 8 rows -
v_SrcData[0] = VecLoadAlignedF32(p_Src, ui_ColDataOffset);
v_SrcData[1] = VecLoadAlignedF32(p_Src, src_pitch + ui_ColDataOffset);
v_SrcData[2] = VecLoadAlignedF32(p_Src, 2*src_pitch + ui_ColDataOffset);
v_SrcData[3] = VecLoadAlignedF32(p_Src, 3*src_pitch + ui_ColDataOffset);
p_Src = (v128f_t*)(((char*)p_Src) + 4*src_pitch);
Transpose4FloatVecs(v_SrcData);
v_SrcData[4] = VecLoadAlignedF32(p_Src, ui_ColDataOffset);
v_SrcData[5] = VecLoadAlignedF32(p_Src, src_pitch + ui_ColDataOffset);
v_SrcData[6] = VecLoadAlignedF32(p_Src, 2*src_pitch + ui_ColDataOffset);
v_SrcData[7] = VecLoadAlignedF32(p_Src, 3*src_pitch + ui_ColDataOffset);
p_Src = (v128f_t*)(((char*)p_Src) + 4*src_pitch);
Transpose4FloatVecs(&v_SrcData[4]);
CachePrefetch4Start(p_Dest, dst_pitch);
for (unsigned int ui_RowGrp=0; ui_RowGrp<(k_Rows/4); ++ui_RowGrp)
{
v128f_t v_Results[4];
// load 4 more rows (each time through this loop the previous ones have been shifted up into v_SrcData[4] to [7]
v_SrcData[8] = VecLoadAlignedF32(p_Src, ui_ColDataOffset);
v_SrcData[9] = VecLoadAlignedF32(p_Src, src_pitch + ui_ColDataOffset);
v_SrcData[10] = VecLoadAlignedF32(p_Src, 2*src_pitch + ui_ColDataOffset);
v_SrcData[11] = VecLoadAlignedF32(p_Src, 3*src_pitch + ui_ColDataOffset);
p_Src = (v128f_t*)(((char*)p_Src) + 4*src_pitch);
Transpose4FloatVecs(&v_SrcData[8]);
for (int i_Row=0; i_Row<4; ++i_Row)
{
// Now filter the column data (the 4 columns are now in elements 0,4,8; 1,5,9; 2,6,10; 3,7,11)
v_Results[0] = sixtap_fp_FilterKernelAndAdvance(v_SrcData[0], v_SrcData[4], v_SrcData[ 8], v_VFilter[0], v_VFilter[1]);
v_Results[1] = sixtap_fp_FilterKernelAndAdvance(v_SrcData[1], v_SrcData[5], v_SrcData[ 9], v_VFilter[0], v_VFilter[1]);
v_Results[2] = sixtap_fp_FilterKernelAndAdvance(v_SrcData[2], v_SrcData[6], v_SrcData[10], v_VFilter[0], v_VFilter[1]);
v_Results[3] = sixtap_fp_FilterKernelAndAdvance(v_SrcData[3], v_SrcData[7], v_SrcData[11], v_VFilter[0], v_VFilter[1]);
v_Results[0] = sixtap_fp_FilterKernelMerge(v_Results);
// To store we need to load the current line, overwrite the four bytes of the current column group, and store back out
v128i_t v_ResultConv = sixtap_fp_FilterConvert(v_Results[0], v_SmallAmount);
sixtap_fp_vert_StoreRowValues<k_Cols>(v_ResultConv, p_Dest, ui_ColGrp);
#if DEBUG_OPTIMISED_FILTERS
for (unsigned int ui_Debug_Col=0; ui_Debug_Col<4; ++ui_Debug_Col)
{
if (p_Dest[ui_Debug_Col + (4*ui_ColGrp)] != p_DebugDest[ui_Debug_Col + (4*ui_ColGrp)] )
{
printf("Bad stuff in VFilter. Row %2d col %2d %3d off\n", ui_RowGrp*4 + i_Row, ui_ColGrp*4 + ui_Debug_Col, (int)(p_Dest[ui_Debug_Col + (4*ui_ColGrp)]) - p_DebugDest[ui_Debug_Col + (4*ui_ColGrp)]);
}
}
p_DebugDest += debug_src_pitch;
#endif
CachePrefetch4Next(p_Dest, dst_pitch);
p_Dest += dst_pitch;
}
}
}
}
else
{
PRF_Scoped("sixtap_vert<%d,%d> bypassed", k_Cols, k_Rows);
// start from the 3rd row as the first two are only used for vertical filtering
v128f_t* p_Src = (v128f_t*)(((char*)src) + (src_pitch * 2));
unsigned char* p_Dest = dst;
#if DEBUG_OPTIMISED_FILTERS
unsigned char* p_DebugDest = debug_src;
#endif
// just pack the values from the src buffer and store in the dest buffer
for (unsigned int ui_Row=0; ui_Row<k_Rows; ++ui_Row)
{
sixtap_fp_vert_PassthroughValues<k_Cols>(p_Src, p_Dest);
#if DEBUG_OPTIMISED_FILTERS
for (unsigned int ui_Debug_Col=0; ui_Debug_Col<k_Cols; ++ui_Debug_Col)
{
if (p_Dest[ui_Debug_Col] != p_DebugDest[ui_Debug_Col] )
{
printf("Bad stuff in VFilter-bypass. %d off\n", (int)(p_Dest[ui_Debug_Col] - p_DebugDest[ui_Debug_Col]));
}
}
p_DebugDest += debug_src_pitch;
#endif
p_Dest += dst_pitch;
p_Src = (v128f_t*)(((char*)p_Src) + src_pitch);
}
}
}
//////////////////////////////////////////////////////////////////////////
#if DEBUG_OPTIMISED_FILTERS
extern "C" void filter_block2d_first_pass(unsigned char *src_ptr, int *output_ptr, unsigned int src_pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, const short *vp8_filter);
extern "C" void filter_block2d_second_pass(int *src_ptr, unsigned char *output_ptr, int output_pitch, unsigned int src_pixels_per_line, unsigned int pixel_step, unsigned int output_height, unsigned int output_width, const short *vp8_filter);
#endif
extern "C"
void vp8_sixtap_predict16x16_durango(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch)
{
const int i_TempBufferX = 4; // 16 float elements
const int i_TempBufferY = 24; // we only need 21, but they need to be processed in groups of 4 during the vertical filtering
v128f_t temp_buffer[i_TempBufferX * i_TempBufferY];
const unsigned int u_TempBufferPitch = i_TempBufferX * sizeof(v128f_t);
#if DEBUG_OPTIMISED_FILTERS
// duplicate the source buffer and perform the c-based filters on it
const short *HFilter;
const short *VFilter;
int FData[21*24]; // Temp data buffer used in filtering
unsigned char temp_dest[16*16];
HFilter = vp8_sub_pel_filters[xofst];
VFilter = vp8_sub_pel_filters[yofst];
filter_block2d_first_pass(src - (2 * src_pitch), FData, src_pitch, 1, 21, 16, HFilter);
vp8_sixtap_predict_durango_horiz<16, 16>(src, src_pitch, xofst, yofst, temp_buffer, u_TempBufferPitch, FData, 16);
filter_block2d_second_pass(FData + 32, temp_dest, 16, 16, 16, 16, 16, VFilter);
vp8_sixtap_predict_durango_vert<16, 16>(temp_buffer, u_TempBufferPitch, xofst, yofst, dst, dst_pitch, temp_dest, 16 );
#else
vp8_sixtap_predict_durango_horiz<16, 16>(src, src_pitch, xofst, yofst, temp_buffer, u_TempBufferPitch);
vp8_sixtap_predict_durango_vert<16, 16>(temp_buffer, u_TempBufferPitch, xofst, yofst, dst, dst_pitch);
#endif
}
extern "C"
void vp8_sixtap_predict8x8_durango(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch)
{
const int i_TempBufferX = 2; // 8 float elements
const int i_TempBufferY = 16; // we only need 13 (8 + 3 + 2), but they need to be processed in groups of 4 during the vertical filtering
v128f_t temp_buffer[i_TempBufferX * i_TempBufferY];
const unsigned int u_TempBufferPitch = i_TempBufferX * sizeof(v128f_t);
#if DEBUG_OPTIMISED_FILTERS
const short *HFilter;
const short *VFilter;
int FData[13*16]; // Temp data buffer used in filtering
unsigned char temp_dest[8*8];
HFilter = vp8_sub_pel_filters[xofst];
VFilter = vp8_sub_pel_filters[yofst];
filter_block2d_first_pass(src - (2 * src_pitch), FData, src_pitch, 1, 13, 8, HFilter);
vp8_sixtap_predict_durango_horiz<8, 8>(src, src_pitch, xofst, yofst, temp_buffer, u_TempBufferPitch, FData, 8);
filter_block2d_second_pass(FData + 16, temp_dest, 8, 8, 8, 8, 8, VFilter);
vp8_sixtap_predict_durango_vert<8, 8>(temp_buffer, u_TempBufferPitch, xofst, yofst, dst, dst_pitch, temp_dest, 8 );
for (unsigned int ui_Row=0; ui_Row<8; ++ui_Row)
{
for (unsigned int ui_Col=0; ui_Col<8; ++ui_Col)
{
unsigned char dst_val = dst[ui_Row*dst_pitch + ui_Col];
if (dst_val != temp_dest[ui_Row*8 + ui_Col])
{
printf("Incorrect result from 8x8 filter at col %d row %d, with xofst %d and yofst %d\n", ui_Col, ui_Row, xofst, yofst);
}
}
}
#else
vp8_sixtap_predict_durango_horiz<8, 8>(src, src_pitch, xofst, yofst, temp_buffer, u_TempBufferPitch);
vp8_sixtap_predict_durango_vert<8, 8>(temp_buffer, u_TempBufferPitch, xofst, yofst, dst, dst_pitch );
#endif
}
extern "C"
void vp8_sixtap_predict8x4_durango(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch)
{
const int i_TempBufferX = 2; // 8 float elements
const int i_TempBufferY = 12; // we only need 9 (4 + 3 + 2), but they need to be processed in groups of 4 during the vertical filtering
v128f_t temp_buffer[i_TempBufferX * i_TempBufferY];
const unsigned int i_TempBufferPitch = i_TempBufferX * sizeof(v128f_t);
#if DEBUG_OPTIMISED_FILTERS
const short *HFilter;
const short *VFilter;
int FData[9*8]; // Temp data buffer used in filtering
unsigned char temp_dest[4*8];
HFilter = vp8_sub_pel_filters[xofst];
VFilter = vp8_sub_pel_filters[yofst];
filter_block2d_first_pass(src - (2 * src_pitch), FData, src_pitch, 1, 9, 8, HFilter);
vp8_sixtap_predict_durango_horiz<8, 4>(src, src_pitch, xofst, yofst, temp_buffer, i_TempBufferPitch, FData, 8);
filter_block2d_second_pass(FData + 16, temp_dest, 8, 8, 8, 4, 8, VFilter);
vp8_sixtap_predict_durango_vert<8, 4>(temp_buffer, i_TempBufferPitch, xofst, yofst, dst, dst_pitch, temp_dest, 8 );
for (unsigned int ui_Row=0; ui_Row<4; ++ui_Row)
{
for (unsigned int ui_Col=0; ui_Col<8; ++ui_Col)
{
unsigned char dst_val = dst[ui_Row*dst_pitch + ui_Col];
if (dst_val != temp_dest[ui_Row*8 + ui_Col])
{
printf("Incorrect result from 8x4 filter at col %d row %d, with xofst %d and yofst %d\n", ui_Col, ui_Row, xofst, yofst);
}
}
}
#else
vp8_sixtap_predict_durango_horiz<8, 4>(src, src_pitch, xofst, yofst, temp_buffer, i_TempBufferPitch);
vp8_sixtap_predict_durango_vert<8, 4>(temp_buffer, i_TempBufferPitch, xofst, yofst, dst, dst_pitch );
#endif
}
extern "C"
void vp8_sixtap_predict4x4_durango(unsigned char *src, int src_pitch, int xofst, int yofst, unsigned char *dst, int dst_pitch)
{
const int i_TempBufferX = 1; // 4 float elements
const int i_TempBufferY = 12; // we only need 9 (4 + 3 + 2), but they need to be processed in groups of 4 during the vertical filtering
v128f_t temp_buffer[i_TempBufferX * i_TempBufferY];
const unsigned int i_TempBufferPitch = i_TempBufferX * sizeof(v128f_t);
#if DEBUG_OPTIMISED_FILTERS
const short *HFilter;
const short *VFilter;
int FData[9*4]; // Temp data buffer used in filtering
unsigned char temp_dest[4*4];
HFilter = vp8_sub_pel_filters[xofst];
VFilter = vp8_sub_pel_filters[yofst];
filter_block2d_first_pass(src - (2 * src_pitch), FData, src_pitch, 1, 9, 4, HFilter);
vp8_sixtap_predict_durango_horiz<4, 4>(src, src_pitch, xofst, yofst, temp_buffer, i_TempBufferPitch, FData, 4);
filter_block2d_second_pass(FData + 8, temp_dest, 4, 4, 4, 4, 4, VFilter);
vp8_sixtap_predict_durango_vert<4, 4>(temp_buffer, i_TempBufferPitch, xofst, yofst, dst, dst_pitch, temp_dest, 4 );
for (unsigned int ui_Row=0; ui_Row<4; ++ui_Row)
{
for (unsigned int ui_Col=0; ui_Col<4; ++ui_Col)
{
unsigned char dst_val = dst[ui_Row*dst_pitch + ui_Col];
if (dst_val != temp_dest[ui_Row*4 + ui_Col])
{
printf("Incorrect result from 4x4 filter at col %d row %d, with xofst %d and yofst %d\n", ui_Col, ui_Row, xofst, yofst);
}
}
}
#else
vp8_sixtap_predict_durango_horiz<4, 4>(src, src_pitch, xofst, yofst, temp_buffer, i_TempBufferPitch);
vp8_sixtap_predict_durango_vert<4, 4>(temp_buffer, i_TempBufferPitch, xofst, yofst, dst, dst_pitch );
#endif
}
#endif //defined(DURANGO)