diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d3da86b..d27905a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,15 @@ message( STATUS "CMAKE_MODULE_PATH: updating module path to: ${CMAKE_MODULE_PATH include( vvdecCompilerSupport ) detect_target_architecture( VVDEC_TARGET_ARCH ) + +set( VVDEC_X86_SIMD_DEFAULT TRUE ) +if( MSVC AND MSVC_VERSION GREATER_EQUAL 1951 AND VVDEC_TARGET_ARCH STREQUAL "AARCH64" ) + message( WARNING "Setting default SIMD-Everywhere X86 to ARM translation to off when using" + " Microsoft ARM compiler (>=19.51) due to compiler bugs." + " (VVDEC_ENABLE_X86_SIMD=FALSE)" ) + set( VVDEC_X86_SIMD_DEFAULT FALSE ) +endif() + if( VVDEC_TARGET_ARCH MATCHES "ARM\|AARCH64" ) set( VVDEC_ARM_SIMD_DEFAULT TRUE ) @@ -50,7 +59,7 @@ if( VVDEC_TARGET_ARCH MATCHES "LOONGARCH64" ) endif() # we enable x86 intrinsics for all target architectures, because they are implemented through simd-everywhere on non-x86 -set( VVDEC_ENABLE_X86_SIMD TRUE CACHE BOOL "Enable x86 intrinsics" ) +set( VVDEC_ENABLE_X86_SIMD ${VVDEC_X86_SIMD_DEFAULT} CACHE BOOL "Enable x86 intrinsics" ) set( VVDEC_ENABLE_ARM_SIMD ${VVDEC_ARM_SIMD_DEFAULT} CACHE BOOL "Enable Arm intrinsics" ) set( VVDEC_ENABLE_ARM_SIMD_RDM ${FLAG_rdm} CACHE BOOL "Enable Arm RDM intrinsics" ) set( VVDEC_ENABLE_ARM_SIMD_SVE ${FLAG_sve} CACHE BOOL "Enable Arm SVE intrinsics" ) diff --git a/source/Lib/CommonLib/TrQuant_EMT.h b/source/Lib/CommonLib/TrQuant_EMT.h index b76aac04..a659ac55 100644 --- a/source/Lib/CommonLib/TrQuant_EMT.h +++ b/source/Lib/CommonLib/TrQuant_EMT.h @@ -62,6 +62,11 @@ struct TCoeffOps void initTCoeffOpsX86(); template void _initTCoeffOpsX86(); +#endif +#if defined( TARGET_SIMD_ARM ) && ENABLE_SIMD_TCOEFF_OPS + void initTCoeffOpsARM(); + template + void _initTCoeffOpsARM(); #endif void( *cpyResiClip[7] ) ( const TCoeff* src, Pel* dst, ptrdiff_t stride, unsigned width, unsigned height, const TCoeff outputMin, const TCoeff outputMax, const TCoeff round, const TCoeff shift ); void( *fastInvCore[5] ) ( const TMatrixCoeff* it, const TCoeff* src, TCoeff* dst, unsigned lines, unsigned reducedLines, unsigned rows ); diff --git a/source/Lib/CommonLib/arm/InitARM.cpp b/source/Lib/CommonLib/arm/InitARM.cpp index fd8ffd66..da9fa283 100644 --- a/source/Lib/CommonLib/arm/InitARM.cpp +++ b/source/Lib/CommonLib/arm/InitARM.cpp @@ -145,15 +145,15 @@ void LoopFilter::initLoopFilterARM() } #endif -//# if ENABLE_SIMD_TCOEFF_OPS -//void TCoeffOps::initTCoeffOpsARM() -//{ -// auto vext = read_arm_extension_flags(); -// if( vext >= NEON ) -// { -// _initTCoeffOpsARM(); -// } -//} +#if ENABLE_SIMD_TCOEFF_OPS +void TCoeffOps::initTCoeffOpsARM() +{ + auto vext = read_arm_extension_flags(); + if( vext >= NEON ) + { + _initTCoeffOpsARM(); + } +} //void TrQuant::initTrQuantARM() //{ @@ -163,7 +163,7 @@ void LoopFilter::initLoopFilterARM() // _initTrQuantARM(); // } //} -//# endif +#endif //# if ENABLE_SIMD_OPT_INTRAPRED //void IntraPrediction::initIntraPredictionARM() diff --git a/source/Lib/CommonLib/arm/neon/Trafo_neon.cpp b/source/Lib/CommonLib/arm/neon/Trafo_neon.cpp new file mode 100644 index 00000000..9db5f5db --- /dev/null +++ b/source/Lib/CommonLib/arm/neon/Trafo_neon.cpp @@ -0,0 +1,138 @@ +/* ----------------------------------------------------------------------------- +The copyright in this software is being made available under the Clear BSD +License, included below. No patent rights, trademark rights and/or +other Intellectual Property Rights other than the copyrights concerning +the Software are granted under this license. + +The Clear BSD License + +Copyright (c) 2018-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVdeC Authors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted (subject to the limitations in the disclaimer below) provided that +the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY +THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +------------------------------------------------------------------------------------------- */ +/** + * \file Trafo_neon.cpp + * \brief Neon implementation of selected TCoeffOps kernels. + */ + +#include "CommonDefARM.h" +#include "CommonLib/CommonDef.h" +#include "TrQuant_EMT.h" + +#if defined( TARGET_SIMD_ARM ) && ENABLE_SIMD_TCOEFF_OPS + +namespace vvdec +{ + +template +void fastInvCore_neon( const TMatrixCoeff* it, const TCoeff* src, TCoeff* dst, unsigned lines, unsigned reducedLines, + unsigned rows ) +{ + static_assert( trSize % 4 == 0, "trSize should be a multiple of four" ); + CHECKD( rows == 0, "rows should be non-zero" ); + + unsigned i = 0; + for( ; i != ( reducedLines & ~3U ); i += 4 ) + { + unsigned j = 0; + do + { + const TCoeff* srci = src + i; + const TMatrixCoeff* itj = it + j; + TCoeff* dstij = dst + i * trSize + j; + + int32x4_t d0 = vld1q_s32( dstij + 0 * trSize ); + int32x4_t d1 = vld1q_s32( dstij + 1 * trSize ); + int32x4_t d2 = vld1q_s32( dstij + 2 * trSize ); + int32x4_t d3 = vld1q_s32( dstij + 3 * trSize ); + + unsigned k = rows; + do + { + int16x4_t s = vmovn_s32( vld1q_s32( srci ) ); + int16x4_t c = vld1_s16( itj ); + + d0 = vmlal_lane_s16( d0, c, s, 0 ); + d1 = vmlal_lane_s16( d1, c, s, 1 ); + d2 = vmlal_lane_s16( d2, c, s, 2 ); + d3 = vmlal_lane_s16( d3, c, s, 3 ); + + srci += lines; + itj += trSize; + } while( --k != 0 ); + + vst1q_s32( dstij + 0 * trSize, d0 ); + vst1q_s32( dstij + 1 * trSize, d1 ); + vst1q_s32( dstij + 2 * trSize, d2 ); + vst1q_s32( dstij + 3 * trSize, d3 ); + + j += 4; + } while( j != trSize ); + } + + for( ; i != reducedLines; ++i ) + { + unsigned j = 0; + do + { + const TCoeff* srci = src + i; + const TMatrixCoeff* itj = it + j; + TCoeff* dstij = dst + i * trSize + j; + + int32_t d0 = *dstij; + unsigned k = rows; + do + { + d0 += *srci * *itj; + + srci += lines; + itj += trSize; + } while( --k != 0 ); + + *dstij = d0; + } while( ++j != trSize ); + } +} + +template<> +void TCoeffOps::_initTCoeffOpsARM() +{ + fastInvCore[0] = fastInvCore_neon<4>; + fastInvCore[1] = fastInvCore_neon<8>; + fastInvCore[2] = fastInvCore_neon<16>; + fastInvCore[3] = fastInvCore_neon<32>; + fastInvCore[4] = fastInvCore_neon<64>; +} + +} // namespace vvdec + +#endif diff --git a/source/Lib/DecoderLib/DecLibRecon.cpp b/source/Lib/DecoderLib/DecLibRecon.cpp index 78804417..73a61962 100644 --- a/source/Lib/DecoderLib/DecLibRecon.cpp +++ b/source/Lib/DecoderLib/DecLibRecon.cpp @@ -124,6 +124,9 @@ DecLibRecon::DecLibRecon() #if ENABLE_SIMD_TCOEFF_OPS && defined( TARGET_SIMD_X86 ) g_tCoeffOps.initTCoeffOpsX86(); #endif +#if ENABLE_SIMD_TCOEFF_OPS && defined( TARGET_SIMD_ARM ) + g_tCoeffOps.initTCoeffOpsARM(); +#endif } void DecLibRecon::create( ThreadPool* threadPool, unsigned instanceId, bool upscaleOutputEnabled ) diff --git a/tests/vvdec_unit_test/vvdec_unit_test.cpp b/tests/vvdec_unit_test/vvdec_unit_test.cpp index b4a65366..3fe13764 100644 --- a/tests/vvdec_unit_test/vvdec_unit_test.cpp +++ b/tests/vvdec_unit_test/vvdec_unit_test.cpp @@ -282,6 +282,9 @@ static bool test_TCoeffOps() #if defined( TARGET_SIMD_X86 ) opt.initTCoeffOpsX86(); #endif +#if defined( TARGET_SIMD_ARM ) + opt.initTCoeffOpsARM(); +#endif unsigned num_cases = NUM_CASES; bool passed = true;