1003 lines
37 KiB
C++
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)
|